diff options
author | HampusM <hampus@hampusmat.com> | 2025-04-08 20:20:33 +0200 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2025-04-08 21:01:32 +0200 |
commit | b982b205373f445db9ced7f3cf13c1156ad8a40a (patch) | |
tree | 1d81cf1e264a2ff33da24a7072b51cc907ef9a83 /ecs/src | |
parent | 402b66282bd1062a36bd7fed793b6014bdb286b2 (diff) |
feat(ecs): add support for component data not implementing Component
Diffstat (limited to 'ecs/src')
-rw-r--r-- | ecs/src/actions.rs | 42 | ||||
-rw-r--r-- | ecs/src/component.rs | 197 | ||||
-rw-r--r-- | ecs/src/lib.rs | 69 |
3 files changed, 158 insertions, 150 deletions
diff --git a/ecs/src/actions.rs b/ecs/src/actions.rs index 7dff3a5..f366b4c 100644 --- a/ecs/src/actions.rs +++ b/ecs/src/actions.rs @@ -1,11 +1,7 @@ use std::marker::PhantomData; use std::sync::{Arc, Weak}; -use crate::component::{ - Component, - Metadata as ComponentMetadata, - Sequence as ComponentSequence, -}; +use crate::component::{Parts as ComponentParts, Sequence as ComponentSequence}; use crate::system::{Param as SystemParam, System}; use crate::uid::{Kind as UidKind, Uid}; use crate::{ActionQueue, World}; @@ -23,10 +19,8 @@ impl<'world> Actions<'world> /// Queues up a entity to spawn at the end of the current tick. pub fn spawn<Comps: ComponentSequence>(&mut self, components: Comps) { - self.action_queue.push(Action::Spawn( - components.into_array().into(), - EventIds { ids: Comps::added_event_ids() }, - )); + self.action_queue + .push(Action::Spawn(components.into_parts_array().into())); } /// Queues up despawning a entity at the end of the current tick. @@ -50,26 +44,28 @@ impl<'world> Actions<'world> self.action_queue.push(Action::AddComponents( entity_uid, - components.into_array().into(), - EventIds { ids: Comps::added_event_ids() }, + components.into_parts_array().into(), )); } /// Queues up removing component(s) from a entity at the end of the current tick. - pub fn remove_components<Comps>(&mut self, entity_uid: Uid) - where - Comps: ComponentSequence, + pub fn remove_components( + &mut self, + entity_uid: Uid, + component_ids: impl IntoIterator<Item = Uid>, + ) { debug_assert_eq!(entity_uid.kind(), UidKind::Entity); - if Comps::COUNT == 0 { + let mut component_ids = component_ids.into_iter().peekable(); + + if component_ids.peek().is_none() { return; } self.action_queue.push(Action::RemoveComponents( entity_uid, - Comps::metadata().into_iter().collect(), - EventIds { ids: Comps::removed_event_ids() }, + component_ids.collect(), )); } @@ -159,19 +155,13 @@ impl Ref<'_> } } -#[derive(Debug)] -pub(crate) struct EventIds -{ - pub(crate) ids: Vec<Uid>, -} - /// A action for a [`System`] to perform. #[derive(Debug)] pub(crate) enum Action { - Spawn(Vec<(Uid, Box<dyn Component>)>, EventIds), + Spawn(Vec<ComponentParts>), Despawn(Uid), - AddComponents(Uid, Vec<(Uid, Box<dyn Component>)>, EventIds), - RemoveComponents(Uid, Vec<ComponentMetadata>, EventIds), + AddComponents(Uid, Vec<ComponentParts>), + RemoveComponents(Uid, Vec<Uid>), Stop, } diff --git a/ecs/src/component.rs b/ecs/src/component.rs index 4516b93..207c329 100644 --- a/ecs/src/component.rs +++ b/ecs/src/component.rs @@ -5,11 +5,7 @@ use std::ops::{Deref, DerefMut}; use seq_macro::seq; -use crate::event::component::{ - Added as ComponentAddedEvent, - Kind as ComponentEventKind, - Removed as ComponentRemovedEvent, -}; +use crate::event::component::Kind as ComponentEventKind; use crate::lock::{ Error as LockError, MappedReadGuard, @@ -80,15 +76,9 @@ pub trait Sequence /// The number of components in this component sequence. const COUNT: usize; - type Array: Array<(Uid, Box<dyn Component>)>; - - fn into_array(self) -> Self::Array; - - fn metadata() -> impl Array<Metadata>; + type PartsArray: Array<Parts>; - fn added_event_ids() -> Vec<Uid>; - - fn removed_event_ids() -> Vec<Uid>; + fn into_parts_array(self) -> Self::PartsArray; } /// A mutable or immutable reference to a component. @@ -143,30 +133,32 @@ pub trait HandleFromEntityComponentRef<'comp>: Sized } #[derive(Debug)] -pub struct Handle<'a, ComponentT: Component> +pub struct Handle<'a, ComponentData: 'static> { - inner: MappedReadGuard<'a, ComponentT>, + inner: MappedReadGuard<'a, ComponentData>, } -impl<'a, ComponentT: Component> Handle<'a, ComponentT> +impl<'a, ComponentData: 'static> Handle<'a, ComponentData> { pub(crate) fn new(inner: ReadGuard<'a, Box<dyn Any>>) -> Self { Self { inner: inner.map(|component| { - component.downcast_ref::<ComponentT>().unwrap_or_else(|| { - panic!( - "Failed to downcast component to type {}", - type_name::<ComponentT>() - ); - }) + component + .downcast_ref::<ComponentData>() + .unwrap_or_else(|| { + panic!( + "Failed to downcast component to type {}", + type_name::<ComponentData>() + ); + }) }), } } } -impl<'comp, ComponentT: Component> HandleFromEntityComponentRef<'comp> - for Handle<'comp, ComponentT> +impl<'comp, ComponentData: 'static> HandleFromEntityComponentRef<'comp> + for Handle<'comp, ComponentData> { type Error = HandleError; @@ -187,9 +179,9 @@ impl<'comp, ComponentT: Component> HandleFromEntityComponentRef<'comp> } } -impl<ComponentT: Component> Deref for Handle<'_, ComponentT> +impl<ComponentData: 'static> Deref for Handle<'_, ComponentData> { - type Target = ComponentT; + type Target = ComponentData; fn deref(&self) -> &Self::Target { @@ -198,30 +190,32 @@ impl<ComponentT: Component> Deref for Handle<'_, ComponentT> } #[derive(Debug)] -pub struct HandleMut<'a, ComponentT: Component> +pub struct HandleMut<'a, ComponentData: 'static> { - inner: MappedWriteGuard<'a, ComponentT>, + inner: MappedWriteGuard<'a, ComponentData>, } -impl<'a, ComponentT: Component> HandleMut<'a, ComponentT> +impl<'a, ComponentData: 'static> HandleMut<'a, ComponentData> { pub(crate) fn new(inner: WriteGuard<'a, Box<dyn Any>>) -> Self { Self { inner: inner.map(|component| { - component.downcast_mut::<ComponentT>().unwrap_or_else(|| { - panic!( - "Failed to downcast component to type {}", - type_name::<ComponentT>() - ); - }) + component + .downcast_mut::<ComponentData>() + .unwrap_or_else(|| { + panic!( + "Failed to downcast component to type {}", + type_name::<ComponentData>() + ); + }) }), } } } -impl<'comp, ComponentT: Component> HandleFromEntityComponentRef<'comp> - for HandleMut<'comp, ComponentT> +impl<'comp, ComponentData: 'static> HandleFromEntityComponentRef<'comp> + for HandleMut<'comp, ComponentData> { type Error = HandleError; @@ -242,9 +236,9 @@ impl<'comp, ComponentT: Component> HandleFromEntityComponentRef<'comp> } } -impl<ComponentT: Component> Deref for HandleMut<'_, ComponentT> +impl<ComponentData: 'static> Deref for HandleMut<'_, ComponentData> { - type Target = ComponentT; + type Target = ComponentData; fn deref(&self) -> &Self::Target { @@ -252,7 +246,7 @@ impl<ComponentT: Component> Deref for HandleMut<'_, ComponentT> } } -impl<ComponentT: Component> DerefMut for HandleMut<'_, ComponentT> +impl<ComponentData: 'static> DerefMut for HandleMut<'_, ComponentData> { fn deref_mut(&mut self) -> &mut Self::Target { @@ -277,49 +271,18 @@ pub struct AcquireComponentLockFailed(LockError); macro_rules! inner { ($c: tt) => { seq!(I in 0..=$c { - impl<#(IntoComp~I,)*> Sequence for (#(IntoComp~I,)*) - where - #( - for<'comp> IntoComp~I: Into<Component: Component>, - )* + impl<#(IntoCompParts~I: IntoParts,)*> Sequence for (#(IntoCompParts~I,)*) { const COUNT: usize = $c + 1; - type Array = [(Uid, Box<dyn Component>); $c + 1]; + type PartsArray = [Parts; $c + 1]; - fn into_array(self) -> Self::Array + fn into_parts_array(self) -> Self::PartsArray { [#({ - let (id, component) = self.I.into_component(); - - (id, Box::new(component)) + self.I.into_parts() },)*] } - - fn metadata() -> impl Array<Metadata> - { - [ - #( - Metadata { - id: IntoComp~I::Component::id(), - }, - )* - ] - } - - fn added_event_ids() -> Vec<Uid> - { - vec![ - #(ComponentAddedEvent::<IntoComp~I::Component>::id(),)* - ] - } - - fn removed_event_ids() -> Vec<Uid> - { - vec![ - #(ComponentRemovedEvent::<IntoComp~I::Component>::id(),)* - ] - } } }); }; @@ -331,46 +294,94 @@ seq!(C in 0..=16 { impl Sequence for () { - type Array = [(Uid, Box<dyn Component>); 0]; + type PartsArray = [Parts; 0]; const COUNT: usize = 0; - fn into_array(self) -> Self::Array + fn into_parts_array(self) -> Self::PartsArray { [] } +} + +pub trait IntoParts +{ + fn into_parts(self) -> Parts; +} - fn metadata() -> impl Array<Metadata> +impl<ComponentT> IntoParts for ComponentT +where + ComponentT: Component, +{ + fn into_parts(self) -> Parts { - [] + Parts::builder() + .name(type_name::<Self>()) + .build(Self::id(), self) } +} - fn added_event_ids() -> Vec<Uid> +/// The parts of a component. +#[derive(Debug)] +#[non_exhaustive] +pub struct Parts +{ + id: Uid, + name: &'static str, + data: Box<dyn Any>, +} + +impl Parts +{ + pub fn id(&self) -> Uid + { + self.id + } + + pub fn name(&self) -> &'static str + { + self.name + } + + pub fn builder() -> PartsBuilder { - Vec::new() + PartsBuilder::default() } - fn removed_event_ids() -> Vec<Uid> + pub(crate) fn into_data(self) -> Box<dyn Any> { - Vec::new() + self.data } } -pub trait Into +#[derive(Debug)] +pub struct PartsBuilder { - type Component; - - fn into_component(self) -> (Uid, Self::Component); + name: &'static str, } -impl<ComponentT> Into for ComponentT -where - ComponentT: Component, +impl PartsBuilder { - type Component = Self; + pub fn name(mut self, name: &'static str) -> Self + { + self.name = name; + self + } - fn into_component(self) -> (Uid, Self::Component) + pub fn build<Data: 'static>(self, id: Uid, data: Data) -> Parts + { + Parts { + id, + name: self.name, + data: Box::new(data), + } + } +} + +impl Default for PartsBuilder +{ + fn default() -> Self { - (Self::id(), self) + Self { name: "(unspecified)" } } } diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs index 2c88eef..962c542 100644 --- a/ecs/src/lib.rs +++ b/ecs/src/lib.rs @@ -12,7 +12,11 @@ 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::component::{ + Component, + Parts as ComponentParts, + Sequence as ComponentSequence, +}; use crate::entity::CREATE_STATIC_ENTITIES; use crate::extension::{Collector as ExtensionCollector, Extension}; use crate::lock::{Lock, WriteGuard}; @@ -116,14 +120,16 @@ impl World Self::add_entity_components( entity_uid, - components.into_array(), + components.into_parts_array(), &mut component_storage_lock, ); } - for added_event_id in Comps::added_event_ids() { - self.emit_event_by_id(added_event_id); - } + // TODO: Emit component added events here + + // for added_event_id in Comps::added_event_ids() { + // self.emit_event_by_id(added_event_id); + // } } /// Adds a globally shared singleton value. @@ -368,7 +374,7 @@ impl World for action in active_action_queue.drain(..) { match action { - Action::Spawn(components, component_added_event_ids) => { + Action::Spawn(components) => { { let mut component_storage_lock = self.lock_component_storage_rw(); @@ -392,18 +398,16 @@ impl World self.swap_event_queue(&mut has_swapped_active_queue); } - for comp_added_event_id in component_added_event_ids.ids { - self.emit_event_by_id(comp_added_event_id); - } + // TODO: Emit component added events here + + // for comp_added_event_id in component_added_event_ids.ids { + // self.emit_event_by_id(comp_added_event_id); + // } } Action::Despawn(entity_uid) => { self.despawn_entity(entity_uid, &mut has_swapped_active_queue); } - Action::AddComponents( - entity_uid, - components, - component_added_event_ids, - ) => { + Action::AddComponents(entity_uid, components) => { { let mut component_storage_lock = self.lock_component_storage_rw(); @@ -418,26 +422,22 @@ impl World self.swap_event_queue(&mut has_swapped_active_queue); } + // TODO: Emit component added events here + // TODO: Fix that events are emitted for components that haven't been // added because a error occurred (for example, the entity already has // the component) - for comp_added_event_id in component_added_event_ids.ids { - self.emit_event_by_id(comp_added_event_id); - } + // for comp_added_event_id in component_added_event_ids.ids { + // self.emit_event_by_id(comp_added_event_id); + // } } - Action::RemoveComponents( - entity_uid, - components_metadata, - component_removed_event_ids, - ) => { + Action::RemoveComponents(entity_uid, component_ids) => { { let mut component_storage_lock = self.lock_component_storage_rw(); Self::remove_entity_components( entity_uid, - components_metadata - .iter() - .map(|comp_metadata| comp_metadata.id), + component_ids, &mut component_storage_lock, ); } @@ -446,12 +446,14 @@ impl World self.swap_event_queue(&mut has_swapped_active_queue); } + // TODO: Emit component removed events here + // TODO: Fix that events are emitted for components that haven't been // removed because a error occurred (for example, the entity does not // have the component) - for comp_removed_event_id in component_removed_event_ids.ids { - self.emit_event_by_id(comp_removed_event_id); - } + // for comp_removed_event_id in component_removed_event_ids.ids { + // self.emit_event_by_id(comp_removed_event_id); + // } } Action::Stop => { self.stop.store(true, Ordering::Relaxed); @@ -488,14 +490,18 @@ impl World fn add_entity_components( entity_uid: Uid, - components: impl IntoIterator<Item = (Uid, Box<dyn Component>)>, + components: impl IntoIterator<Item = ComponentParts>, component_storage: &mut ComponentStorage, ) { - for (component_id, component) in components { + for component_parts in components { if let Err(err) = component_storage.add_entity_component( entity_uid, - (component_id, component.name(), component), + ( + component_parts.id(), + component_parts.name(), + component_parts.into_data(), + ), ) { tracing::error!("Failed to add component to entity: {err}"); } @@ -517,6 +523,7 @@ impl World } } + #[allow(dead_code)] fn emit_event_by_id(&self, event_id: Uid) { let query = self.flexible_query( |