mod command_queue; use crate::{ bundle::Bundle, component::Component, entity::{Entities, Entity}, world::World, }; use bevy_utils::tracing::{debug, error}; pub use command_queue::CommandQueue; use std::marker::PhantomData; /// A [`World`] mutation. pub trait Command: Send + Sync + 'static { fn write(self, world: &mut World); } /// A list of commands that will be run to modify a [`World`]. pub struct Commands<'w, 's> { queue: &'s mut CommandQueue, entities: &'w Entities, } impl<'w, 's> Commands<'w, 's> { /// Create a new `Commands` from a queue and a world. pub fn new(queue: &'s mut CommandQueue, world: &'w World) -> Self { Self { queue, entities: world.entities(), } } /// Creates a new empty [`Entity`] and returns an [`EntityCommands`] builder for it. /// /// # Example /// /// ``` /// use bevy_ecs::prelude::*; /// /// fn example_system(mut commands: Commands) { /// // Create a new empty entity and retrieve its id. /// let empty_entity = commands.spawn().id(); /// /// // Create another empty entity, then add some component to it /// commands.spawn() /// // adds a new component bundle to the entity /// .insert_bundle((1usize, 2u32)) /// // adds a single component to the entity /// .insert("hello world"); /// } /// # example_system.system(); /// ``` pub fn spawn<'a>(&'a mut self) -> EntityCommands<'w, 's, 'a> { let entity = self.entities.reserve_entity(); EntityCommands { entity, commands: self, } } /// Returns an [EntityCommands] for the given `entity` (if it exists) or spawns one if it doesn't exist. /// This will return [None] if the `entity` exists with a different generation. /// /// # Note /// Spawning a specific `entity` value is rarely the right choice. Most apps should favor [`Commands::spawn`]. /// This method should generally only be used for sharing entities across apps, and only when they have a /// scheme worked out to share an ID space (which doesn't happen by default). pub fn get_or_spawn<'a>(&'a mut self, entity: Entity) -> EntityCommands<'w, 's, 'a> { self.add(GetOrSpawn { entity }); EntityCommands { entity, commands: self, } } /// Spawns a [Bundle] without pre-allocating an [Entity]. The [Entity] will be allocated when /// this [Command] is applied. pub fn spawn_and_forget(&mut self, bundle: impl Bundle) { self.queue.push(Spawn { bundle }) } /// Creates a new entity with the components contained in `bundle`. /// /// This returns an [`EntityCommands`] builder, which enables inserting more components and /// bundles using a "builder pattern". /// /// Note that `bundle` is a [`Bundle`], which is a collection of components. [`Bundle`] is /// automatically implemented for tuples of components. You can also create your own bundle /// types by deriving [`derive@Bundle`]. /// /// # Example /// /// ``` /// use bevy_ecs::prelude::*; /// /// struct Component1; /// struct Component2; /// /// #[derive(Bundle)] /// struct ExampleBundle { /// a: Component1, /// b: Component2, /// } /// /// fn example_system(mut commands: Commands) { /// // Create a new entity with a component bundle. /// commands.spawn_bundle(ExampleBundle { /// a: Component1, /// b: Component2, /// }); /// /// commands /// // Create a new entity with two components using a "tuple bundle". /// .spawn_bundle((Component1, Component2)) /// // spawn_bundle returns a builder, so you can insert more bundles like this: /// .insert_bundle((1usize, 2u32)) /// // or insert single components like this: /// .insert("hello world"); /// } /// # example_system.system(); /// ``` pub fn spawn_bundle<'a, T: Bundle>(&'a mut self, bundle: T) -> EntityCommands<'w, 's, 'a> { let mut e = self.spawn(); e.insert_bundle(bundle); e } /// Returns an [`EntityCommands`] builder for the requested [`Entity`]. /// /// # Example /// /// ``` /// use bevy_ecs::prelude::*; /// /// fn example_system(mut commands: Commands) { /// // Create a new, empty entity /// let entity = commands.spawn().id(); /// /// commands.entity(entity) /// // adds a new component bundle to the entity /// .insert_bundle((1usize, 2u32)) /// // adds a single component to the entity /// .insert("hello world"); /// } /// # example_system.system(); /// ``` pub fn entity<'a>(&'a mut self, entity: Entity) -> EntityCommands<'w, 's, 'a> { EntityCommands { entity, commands: self, } } /// Equivalent to iterating `bundles_iter` and calling [`Self::spawn`] on each bundle, but /// slightly more performant. pub fn spawn_batch(&mut self, bundles_iter: I) where I: IntoIterator + Send + Sync + 'static, I::Item: Bundle, { self.queue.push(SpawnBatch { bundles_iter }); } /// For a given batch of ([Entity], [Bundle]) pairs, either spawns each [Entity] with the given /// bundle (if the entity does not exist), or inserts the [Bundle] (if the entity already exists). /// This is faster than doing equivalent operations one-by-one. /// /// # Note /// Spawning a specific `entity` value is rarely the right choice. Most apps should use [`Commands::spawn_batch`]. /// This method should generally only be used for sharing entities across apps, and only when they have a scheme /// worked out to share an ID space (which doesn't happen by default). pub fn insert_or_spawn_batch(&mut self, bundles_iter: I) where I: IntoIterator + Send + Sync + 'static, I::IntoIter: Iterator, B: Bundle, { self.queue.push(InsertOrSpawnBatch { bundles_iter }); } /// See [`World::insert_resource`]. pub fn insert_resource(&mut self, resource: T) { self.queue.push(InsertResource { resource }) } /// Queue a resource removal. pub fn remove_resource(&mut self) { self.queue.push(RemoveResource:: { phantom: PhantomData, }); } /// Adds a command directly to the command list. pub fn add(&mut self, command: C) { self.queue.push(command); } } /// A list of commands that will be run to modify an [`Entity`]. pub struct EntityCommands<'w, 's, 'a> { entity: Entity, commands: &'a mut Commands<'w, 's>, } impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> { /// Retrieves the current entity's unique [`Entity`] id. #[inline] pub fn id(&self) -> Entity { self.entity } /// Adds a [`Bundle`] of components to the current entity. pub fn insert_bundle(&mut self, bundle: impl Bundle) -> &mut Self { self.commands.add(InsertBundle { entity: self.entity, bundle, }); self } /// Adds a single [`Component`] to the current entity. /// /// /// # Warning /// /// It's possible to call this with a bundle, but this is likely not intended and /// [`Self::insert_bundle`] should be used instead. If `with` is called with a bundle, the /// bundle itself will be added as a component instead of the bundles' inner components each /// being added. /// /// # Example /// /// `Self::insert` can be chained with [`Commands::spawn`]. /// /// ``` /// use bevy_ecs::prelude::*; /// /// struct Component1; /// struct Component2; /// /// fn example_system(mut commands: Commands) { /// // Create a new entity with `Component1` and `Component2` /// commands.spawn() /// .insert(Component1) /// .insert(Component2); /// /// // Psst! These are also equivalent to the expression above! /// commands.spawn().insert_bundle((Component1, Component2)); /// commands.spawn_bundle((Component1, Component2)); /// } /// # example_system.system(); /// ``` pub fn insert(&mut self, component: impl Component) -> &mut Self { self.commands.add(Insert { entity: self.entity, component, }); self } /// See [`EntityMut::remove_bundle`](crate::world::EntityMut::remove_bundle). pub fn remove_bundle(&mut self) -> &mut Self where T: Bundle, { self.commands.add(RemoveBundle:: { entity: self.entity, phantom: PhantomData, }); self } /// See [`EntityMut::remove`](crate::world::EntityMut::remove). pub fn remove(&mut self) -> &mut Self where T: Component, { self.commands.add(Remove:: { entity: self.entity, phantom: PhantomData, }); self } /// Despawns only the specified entity, not including its children. pub fn despawn(&mut self) { self.commands.add(Despawn { entity: self.entity, }) } /// Returns the underlying `[Commands]`. pub fn commands(&mut self) -> &mut Commands<'w, 's> { self.commands } } #[derive(Debug)] pub struct Spawn { pub bundle: T, } impl Command for Spawn where T: Bundle, { fn write(self, world: &mut World) { world.spawn().insert_bundle(self.bundle); } } pub struct GetOrSpawn { entity: Entity, } impl Command for GetOrSpawn { fn write(self, world: &mut World) { world.get_or_spawn(self.entity); } } pub struct SpawnBatch where I: IntoIterator, I::Item: Bundle, { pub bundles_iter: I, } impl Command for SpawnBatch where I: IntoIterator + Send + Sync + 'static, I::Item: Bundle, { fn write(self, world: &mut World) { world.spawn_batch(self.bundles_iter); } } pub struct InsertOrSpawnBatch where I: IntoIterator + Send + Sync + 'static, B: Bundle, I::IntoIter: Iterator, { pub bundles_iter: I, } impl Command for InsertOrSpawnBatch where I: IntoIterator + Send + Sync + 'static, B: Bundle, I::IntoIter: Iterator, { fn write(self, world: &mut World) { if let Err(invalid_entities) = world.insert_or_spawn_batch(self.bundles_iter) { error!( "Failed to 'insert or spawn' bundle of type {} into the following invalid entities: {:?}", std::any::type_name::(), invalid_entities ); } } } #[derive(Debug)] pub struct Despawn { pub entity: Entity, } impl Command for Despawn { fn write(self, world: &mut World) { if !world.despawn(self.entity) { debug!("Failed to despawn non-existent entity {:?}", self.entity); } } } pub struct InsertBundle { pub entity: Entity, pub bundle: T, } impl Command for InsertBundle where T: Bundle + 'static, { fn write(self, world: &mut World) { world.entity_mut(self.entity).insert_bundle(self.bundle); } } #[derive(Debug)] pub struct Insert { pub entity: Entity, pub component: T, } impl Command for Insert where T: Component, { fn write(self, world: &mut World) { world.entity_mut(self.entity).insert(self.component); } } #[derive(Debug)] pub struct Remove { pub entity: Entity, pub phantom: PhantomData, } impl Command for Remove where T: Component, { fn write(self, world: &mut World) { if let Some(mut entity_mut) = world.get_entity_mut(self.entity) { entity_mut.remove::(); } } } #[derive(Debug)] pub struct RemoveBundle { pub entity: Entity, pub phantom: PhantomData, } impl Command for RemoveBundle where T: Bundle, { fn write(self, world: &mut World) { if let Some(mut entity_mut) = world.get_entity_mut(self.entity) { // remove intersection to gracefully handle components that were removed before running // this command entity_mut.remove_bundle_intersection::(); } } } pub struct InsertResource { pub resource: T, } impl Command for InsertResource { fn write(self, world: &mut World) { world.insert_resource(self.resource); } } pub struct RemoveResource { pub phantom: PhantomData, } impl Command for RemoveResource { fn write(self, world: &mut World) { world.remove_resource::(); } } #[cfg(test)] #[allow(clippy::float_cmp, clippy::approx_constant)] mod tests { use crate::{ component::{ComponentDescriptor, StorageType}, system::{CommandQueue, Commands}, world::World, }; use std::sync::{ atomic::{AtomicUsize, Ordering}, Arc, }; #[derive(Clone, Debug)] struct DropCk(Arc); impl DropCk { fn new_pair() -> (Self, Arc) { let atomic = Arc::new(AtomicUsize::new(0)); (DropCk(atomic.clone()), atomic) } } impl Drop for DropCk { fn drop(&mut self) { self.0.as_ref().fetch_add(1, Ordering::Relaxed); } } #[test] fn commands() { let mut world = World::default(); let mut command_queue = CommandQueue::default(); let entity = Commands::new(&mut command_queue, &world) .spawn_bundle((1u32, 2u64)) .id(); command_queue.apply(&mut world); assert!(world.entities().len() == 1); let results = world .query::<(&u32, &u64)>() .iter(&world) .map(|(a, b)| (*a, *b)) .collect::>(); assert_eq!(results, vec![(1u32, 2u64)]); // test entity despawn { let mut commands = Commands::new(&mut command_queue, &world); commands.entity(entity).despawn(); commands.entity(entity).despawn(); // double despawn shouldn't panic } command_queue.apply(&mut world); let results2 = world .query::<(&u32, &u64)>() .iter(&world) .map(|(a, b)| (*a, *b)) .collect::>(); assert_eq!(results2, vec![]); } #[test] fn remove_components() { let mut world = World::default(); struct DenseDropCk(DropCk); world .register_component(ComponentDescriptor::new::(StorageType::SparseSet)) .unwrap(); let mut command_queue = CommandQueue::default(); let (dense_dropck, dense_is_dropped) = DropCk::new_pair(); let dense_dropck = DenseDropCk(dense_dropck); let (sparse_dropck, sparse_is_dropped) = DropCk::new_pair(); let entity = Commands::new(&mut command_queue, &world) .spawn() .insert_bundle((1u32, 2u64, dense_dropck, sparse_dropck)) .id(); command_queue.apply(&mut world); let results_before = world .query::<(&u32, &u64)>() .iter(&world) .map(|(a, b)| (*a, *b)) .collect::>(); assert_eq!(results_before, vec![(1u32, 2u64)]); // test component removal Commands::new(&mut command_queue, &world) .entity(entity) .remove::() .remove_bundle::<(u32, u64, DenseDropCk, DropCk)>(); assert_eq!(dense_is_dropped.load(Ordering::Relaxed), 0); assert_eq!(sparse_is_dropped.load(Ordering::Relaxed), 0); command_queue.apply(&mut world); assert_eq!(dense_is_dropped.load(Ordering::Relaxed), 1); assert_eq!(sparse_is_dropped.load(Ordering::Relaxed), 1); let results_after = world .query::<(&u32, &u64)>() .iter(&world) .map(|(a, b)| (*a, *b)) .collect::>(); assert_eq!(results_after, vec![]); let results_after_u64 = world .query::<&u64>() .iter(&world) .copied() .collect::>(); assert_eq!(results_after_u64, vec![]); } #[test] fn remove_resources() { let mut world = World::default(); let mut queue = CommandQueue::default(); { let mut commands = Commands::new(&mut queue, &world); commands.insert_resource(123); commands.insert_resource(456.0); } queue.apply(&mut world); assert!(world.contains_resource::()); assert!(world.contains_resource::()); { let mut commands = Commands::new(&mut queue, &world); // test resource removal commands.remove_resource::(); } queue.apply(&mut world); assert!(!world.contains_resource::()); assert!(world.contains_resource::()); } }