diff options
Diffstat (limited to 'ecs/src/actions.rs')
| -rw-r--r-- | ecs/src/actions.rs | 145 |
1 files changed, 110 insertions, 35 deletions
diff --git a/ecs/src/actions.rs b/ecs/src/actions.rs index e0efeda..549e341 100644 --- a/ecs/src/actions.rs +++ b/ecs/src/actions.rs @@ -1,9 +1,12 @@ +use std::any::type_name; use std::marker::PhantomData; use std::rc::{Rc, Weak}; 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::event::component::Removed; +use crate::pair::Pair; +use crate::system::{Metadata as SystemMetadata, Param as SystemParam}; +use crate::uid::{Kind as UidKind, Uid, WithUidTuple}; use crate::{ActionQueue, World}; /// Used to to queue up actions for a [`World`] to perform. @@ -11,16 +14,23 @@ use crate::{ActionQueue, World}; pub struct Actions<'world> { action_queue: &'world ActionQueue, - action_queue_weak: Weak<ActionQueue>, + world: Option<&'world World>, } -impl<'world> Actions<'world> +impl Actions<'_> { - /// Queues up a entity to spawn at the end of the current tick. - pub fn spawn<Comps: ComponentSequence>(&mut self, components: Comps) + /// Queues up a entity to spawn at the end of the current tick, returning the [`Uid`] + /// that the entity will have. + pub fn spawn<Comps: ComponentSequence>(&mut self, components: Comps) -> Uid { - self.action_queue - .push(Action::Spawn(components.into_parts_array().into())); + let new_entity_uid = Uid::new_unique(UidKind::Entity); + + self.action_queue.push(Action::Spawn( + new_entity_uid, + components.into_parts_array().into(), + )); + + new_entity_uid } /// Queues up despawning a entity at the end of the current tick. @@ -28,6 +38,31 @@ impl<'world> Actions<'world> { debug_assert_eq!(entity_uid.kind(), UidKind::Entity); + let Some(world) = self.world else { + self.action_queue.push(Action::Despawn(entity_uid)); + return; + }; + + let Some(ent) = world.get_entity(entity_uid) else { + tracing::warn!("Cannot entity that doesn't exist"); + return; + }; + + // TODO: Submit all events with a single function call to reduce overhead + for comp_id in ent.component_ids() { + if comp_id.kind() == UidKind::Pair { + continue; + } + + world.event_submitter().submit_event( + &Pair::builder() + .relation::<Removed>() + .target_id(comp_id) + .build(), + entity_uid, + ); + } + self.action_queue.push(Action::Despawn(entity_uid)); } @@ -49,6 +84,7 @@ impl<'world> Actions<'world> } /// Queues up removing component(s) from a entity at the end of the current tick. + #[tracing::instrument(skip(self, component_ids))] pub fn remove_components( &mut self, entity_uid: Uid, @@ -63,10 +99,50 @@ impl<'world> Actions<'world> return; } - self.action_queue.push(Action::RemoveComponents( - entity_uid, - component_ids.collect(), - )); + let Some(world) = self.world else { + self.action_queue.push(Action::RemoveComponents( + entity_uid, + component_ids.collect(), + )); + return; + }; + + let Some(ent) = world.get_entity(entity_uid) else { + tracing::warn!("Cannot remove components from entity that doesn't exist"); + return; + }; + + let component_ids = component_ids + .filter(|comp_id| ent.has_component(*comp_id)) + .collect::<Vec<_>>(); + + if component_ids.is_empty() { + return; + } + + // TODO: Submit all events with a single function call to reduce overhead + for comp_id in &component_ids { + if comp_id.kind() == UidKind::Pair { + continue; + } + + world.event_submitter().submit_event( + &Pair::builder() + .relation::<Removed>() + .target_id(*comp_id) + .build(), + entity_uid, + ); + } + + self.action_queue + .push(Action::RemoveComponents(entity_uid, component_ids)); + } + + /// Queues up removing component(s) from a entity at the end of the current tick. + pub fn remove_comps<Ids: WithUidTuple>(&mut self, entity_uid: Uid) + { + self.remove_components(entity_uid, Ids::uids()); } /// Stops the [`World`]. The world will finish the current tick and that tick will be @@ -79,19 +155,22 @@ impl<'world> Actions<'world> /// Returns a struct which holds a weak reference to the [`World`] that `Actions` /// references and that can be used to aquire a new `Actions` instance if the /// referenced [`World`] is still alive. + /// + /// # Panics + /// This function will panic if `self` was retrieved from a [`WeakRef`]. #[must_use] pub fn to_weak_ref(&self) -> WeakRef { - WeakRef { - action_queue: self.action_queue_weak.clone(), - } - } + let world = self.world.unwrap_or_else(|| { + panic!( + "This function cannot be called if the {} was retrieved from a {}", + type_name::<Self>(), + type_name::<WeakRef>() + ) + }); - fn new(action_queue: &'world Rc<ActionQueue>) -> Self - { - Self { - action_queue, - action_queue_weak: Rc::downgrade(action_queue), + WeakRef { + action_queue: Rc::downgrade(&world.data.action_queue), } } } @@ -100,19 +179,12 @@ impl<'world> SystemParam<'world> for Actions<'world> { type Input = (); - fn initialize<SystemImpl>( - _system: &mut impl System<'world, SystemImpl>, - _input: Self::Input, - ) - { - } - - fn new<SystemImpl>( - _system: &'world impl System<'world, SystemImpl>, - world: &'world World, - ) -> Self + fn new(world: &'world World, _system_metadata: &SystemMetadata) -> Self { - Self::new(&world.data.action_queue) + Self { + action_queue: &world.data.action_queue, + world: Some(world), + } } } @@ -151,7 +223,10 @@ impl Ref<'_> #[must_use] pub fn to_actions(&self) -> Actions<'_> { - Actions::new(&self.action_queue) + Actions { + action_queue: &self.action_queue, + world: None, + } } } @@ -159,7 +234,7 @@ impl Ref<'_> #[derive(Debug)] pub(crate) enum Action { - Spawn(Vec<ComponentParts>), + Spawn(Uid, Vec<ComponentParts>), Despawn(Uid), AddComponents(Uid, Vec<ComponentParts>), RemoveComponents(Uid, Vec<Uid>), |
