summaryrefslogtreecommitdiff
path: root/ecs/src
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2025-04-08 20:20:33 +0200
committerHampusM <hampus@hampusmat.com>2025-04-08 21:01:32 +0200
commitb982b205373f445db9ced7f3cf13c1156ad8a40a (patch)
tree1d81cf1e264a2ff33da24a7072b51cc907ef9a83 /ecs/src
parent402b66282bd1062a36bd7fed793b6014bdb286b2 (diff)
feat(ecs): add support for component data not implementing Component
Diffstat (limited to 'ecs/src')
-rw-r--r--ecs/src/actions.rs42
-rw-r--r--ecs/src/component.rs197
-rw-r--r--ecs/src/lib.rs69
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(