summaryrefslogtreecommitdiff
path: root/ecs/src/actions.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ecs/src/actions.rs')
-rw-r--r--ecs/src/actions.rs145
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>),