pub mod command; pub mod entity_command; #[cfg(feature = "std")] mod parallel_scope; pub use command::Command; pub use entity_command::EntityCommand; #[cfg(feature = "std")] pub use parallel_scope::*; use alloc::boxed::Box; use core::marker::PhantomData; use log::error; use crate::{ self as bevy_ecs, bundle::{Bundle, InsertMode, NoBundleEffect}, change_detection::{MaybeLocation, Mut}, component::{Component, ComponentId, Mutable}, entity::{Entities, Entity, EntityClonerBuilder, EntityDoesNotExistError}, error::{ignore, warn, BevyError, CommandWithEntity, ErrorContext, HandleError}, event::Event, observer::{Observer, TriggerTargets}, resource::Resource, schedule::ScheduleLabel, system::{ Deferred, IntoObserverSystem, IntoSystem, RegisteredSystem, SystemId, SystemInput, SystemParamValidationError, }, world::{ command_queue::RawCommandQueue, unsafe_world_cell::UnsafeWorldCell, CommandQueue, EntityWorldMut, FromWorld, World, }, }; /// A [`Command`] queue to perform structural changes to the [`World`]. /// /// Since each command requires exclusive access to the `World`, /// all queued commands are automatically applied in sequence /// when the `ApplyDeferred` system runs (see [`ApplyDeferred`] documentation for more details). /// /// Each command can be used to modify the [`World`] in arbitrary ways: /// * spawning or despawning entities /// * inserting components on new or existing entities /// * inserting resources /// * etc. /// /// For a version of [`Commands`] that works in parallel contexts (such as /// within [`Query::par_iter`](crate::system::Query::par_iter)) see /// [`ParallelCommands`] /// /// # Usage /// /// Add `mut commands: Commands` as a function argument to your system to get a /// copy of this struct that will be applied the next time a copy of [`ApplyDeferred`] runs. /// Commands are almost always used as a [`SystemParam`](crate::system::SystemParam). /// /// ``` /// # use bevy_ecs::prelude::*; /// fn my_system(mut commands: Commands) { /// // ... /// } /// # bevy_ecs::system::assert_is_system(my_system); /// ``` /// /// # Implementing /// /// Each built-in command is implemented as a separate method, e.g. [`Commands::spawn`]. /// In addition to the pre-defined command methods, you can add commands with any arbitrary /// behavior using [`Commands::queue`], which accepts any type implementing [`Command`]. /// /// Since closures and other functions implement this trait automatically, this allows one-shot, /// anonymous custom commands. /// /// ``` /// # use bevy_ecs::prelude::*; /// # fn foo(mut commands: Commands) { /// // NOTE: type inference fails here, so annotations are required on the closure. /// commands.queue(|w: &mut World| { /// // Mutate the world however you want... /// }); /// # } /// ``` /// /// # Error handling /// /// A [`Command`] can return a [`Result`](crate::error::Result), /// which will be passed to an [error handler](crate::error) if the `Result` is an error. /// /// The [default error handler](crate::error::default_error_handler) panics. /// It can be configured by setting the `GLOBAL_ERROR_HANDLER`. /// /// Alternatively, you can customize the error handler for a specific command /// by calling [`Commands::queue_handled`]. /// /// The [`error`](crate::error) module provides some simple error handlers for convenience. /// /// [`ApplyDeferred`]: crate::schedule::ApplyDeferred pub struct Commands<'w, 's> { queue: InternalQueue<'s>, entities: &'w Entities, } // SAFETY: All commands [`Command`] implement [`Send`] unsafe impl Send for Commands<'_, '_> {} // SAFETY: `Commands` never gives access to the inner commands. unsafe impl Sync for Commands<'_, '_> {} const _: () = { type __StructFieldsAlias<'w, 's> = (Deferred<'s, CommandQueue>, &'w Entities); #[doc(hidden)] pub struct FetchState { state: <__StructFieldsAlias<'static, 'static> as bevy_ecs::system::SystemParam>::State, } // SAFETY: Only reads Entities unsafe impl bevy_ecs::system::SystemParam for Commands<'_, '_> { type State = FetchState; type Item<'w, 's> = Commands<'w, 's>; fn init_state( world: &mut World, system_meta: &mut bevy_ecs::system::SystemMeta, ) -> Self::State { FetchState { state: <__StructFieldsAlias<'_, '_> as bevy_ecs::system::SystemParam>::init_state( world, system_meta, ), } } unsafe fn new_archetype( state: &mut Self::State, archetype: &bevy_ecs::archetype::Archetype, system_meta: &mut bevy_ecs::system::SystemMeta, ) { // SAFETY: Caller guarantees the archetype is from the world used in `init_state` unsafe { <__StructFieldsAlias<'_, '_> as bevy_ecs::system::SystemParam>::new_archetype( &mut state.state, archetype, system_meta, ); }; } fn apply( state: &mut Self::State, system_meta: &bevy_ecs::system::SystemMeta, world: &mut World, ) { <__StructFieldsAlias<'_, '_> as bevy_ecs::system::SystemParam>::apply( &mut state.state, system_meta, world, ); } fn queue( state: &mut Self::State, system_meta: &bevy_ecs::system::SystemMeta, world: bevy_ecs::world::DeferredWorld, ) { <__StructFieldsAlias<'_, '_> as bevy_ecs::system::SystemParam>::queue( &mut state.state, system_meta, world, ); } #[inline] unsafe fn validate_param( state: &Self::State, system_meta: &bevy_ecs::system::SystemMeta, world: UnsafeWorldCell, ) -> Result<(), SystemParamValidationError> { <(Deferred, &Entities) as bevy_ecs::system::SystemParam>::validate_param( &state.state, system_meta, world, ) } #[inline] unsafe fn get_param<'w, 's>( state: &'s mut Self::State, system_meta: &bevy_ecs::system::SystemMeta, world: UnsafeWorldCell<'w>, change_tick: bevy_ecs::component::Tick, ) -> Self::Item<'w, 's> { let(f0, f1) = <(Deferred<'s, CommandQueue>, &'w Entities) as bevy_ecs::system::SystemParam>::get_param(&mut state.state, system_meta, world, change_tick); Commands { queue: InternalQueue::CommandQueue(f0), entities: f1, } } } // SAFETY: Only reads Entities unsafe impl<'w, 's> bevy_ecs::system::ReadOnlySystemParam for Commands<'w, 's> where Deferred<'s, CommandQueue>: bevy_ecs::system::ReadOnlySystemParam, &'w Entities: bevy_ecs::system::ReadOnlySystemParam, { } }; enum InternalQueue<'s> { CommandQueue(Deferred<'s, CommandQueue>), RawCommandQueue(RawCommandQueue), } impl<'w, 's> Commands<'w, 's> { /// Returns a new `Commands` instance from a [`CommandQueue`] and a [`World`]. pub fn new(queue: &'s mut CommandQueue, world: &'w World) -> Self { Self::new_from_entities(queue, &world.entities) } /// Returns a new `Commands` instance from a [`CommandQueue`] and an [`Entities`] reference. pub fn new_from_entities(queue: &'s mut CommandQueue, entities: &'w Entities) -> Self { Self { queue: InternalQueue::CommandQueue(Deferred(queue)), entities, } } /// Returns a new `Commands` instance from a [`RawCommandQueue`] and an [`Entities`] reference. /// /// This is used when constructing [`Commands`] from a [`DeferredWorld`](crate::world::DeferredWorld). /// /// # Safety /// /// * Caller ensures that `queue` must outlive `'w` pub(crate) unsafe fn new_raw_from_entities( queue: RawCommandQueue, entities: &'w Entities, ) -> Self { Self { queue: InternalQueue::RawCommandQueue(queue), entities, } } /// Returns a [`Commands`] with a smaller lifetime. /// /// This is useful if you have `&mut Commands` but need `Commands`. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// fn my_system(mut commands: Commands) { /// // We do our initialization in a separate function, /// // which expects an owned `Commands`. /// do_initialization(commands.reborrow()); /// /// // Since we only reborrowed the commands instead of moving them, we can still use them. /// commands.spawn_empty(); /// } /// # /// # fn do_initialization(_: Commands) {} /// ``` pub fn reborrow(&mut self) -> Commands<'w, '_> { Commands { queue: match &mut self.queue { InternalQueue::CommandQueue(queue) => InternalQueue::CommandQueue(queue.reborrow()), InternalQueue::RawCommandQueue(queue) => { InternalQueue::RawCommandQueue(queue.clone()) } }, entities: self.entities, } } /// Take all commands from `other` and append them to `self`, leaving `other` empty. pub fn append(&mut self, other: &mut CommandQueue) { match &mut self.queue { InternalQueue::CommandQueue(queue) => queue.bytes.append(&mut other.bytes), InternalQueue::RawCommandQueue(queue) => { // SAFETY: Pointers in `RawCommandQueue` are never null unsafe { queue.bytes.as_mut() }.append(&mut other.bytes); } } } /// Spawns a new empty [`Entity`] and returns its corresponding [`EntityCommands`]. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// #[derive(Component)] /// struct Label(&'static str); /// #[derive(Component)] /// struct Strength(u32); /// #[derive(Component)] /// struct Agility(u32); /// /// fn example_system(mut commands: Commands) { /// // Create a new empty entity. /// commands.spawn_empty(); /// /// // Create another empty entity. /// commands.spawn_empty() /// // Add a new component bundle to the entity. /// .insert((Strength(1), Agility(2))) /// // Add a single component to the entity. /// .insert(Label("hello world")); /// } /// # bevy_ecs::system::assert_is_system(example_system); /// ``` /// /// # See also /// /// - [`spawn`](Self::spawn) to spawn an entity with components. /// - [`spawn_batch`](Self::spawn_batch) to spawn many entities /// with the same combination of components. #[track_caller] pub fn spawn_empty(&mut self) -> EntityCommands { let entity = self.entities.reserve_entity(); let mut entity_commands = EntityCommands { entity, commands: self.reborrow(), }; let caller = MaybeLocation::caller(); entity_commands.queue(move |entity: EntityWorldMut| { let index = entity.id().index(); let world = entity.into_world_mut(); let tick = world.change_tick(); // SAFETY: Entity has been flushed unsafe { world.entities_mut().mark_spawn_despawn(index, caller, tick); } }); entity_commands } /// Spawns a new [`Entity`] with the given components /// and returns the entity's corresponding [`EntityCommands`]. /// /// To spawn many entities with the same combination of components, /// [`spawn_batch`](Self::spawn_batch) can be used for better performance. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// #[derive(Component)] /// struct ComponentA(u32); /// #[derive(Component)] /// struct ComponentB(u32); /// /// #[derive(Bundle)] /// struct ExampleBundle { /// a: ComponentA, /// b: ComponentB, /// } /// /// fn example_system(mut commands: Commands) { /// // Create a new entity with a single component. /// commands.spawn(ComponentA(1)); /// /// // Create a new entity with two components using a "tuple bundle". /// commands.spawn((ComponentA(2), ComponentB(1))); /// /// // Create a new entity with a component bundle. /// commands.spawn(ExampleBundle { /// a: ComponentA(3), /// b: ComponentB(2), /// }); /// } /// # bevy_ecs::system::assert_is_system(example_system); /// ``` /// /// # See also /// /// - [`spawn_empty`](Self::spawn_empty) to spawn an entity without any components. /// - [`spawn_batch`](Self::spawn_batch) to spawn many entities /// with the same combination of components. #[track_caller] pub fn spawn(&mut self, bundle: T) -> EntityCommands { let entity = self.entities.reserve_entity(); let mut entity_commands = EntityCommands { entity, commands: self.reborrow(), }; let caller = MaybeLocation::caller(); entity_commands.queue(move |mut entity: EntityWorldMut| { // Store metadata about the spawn operation. // This is the same as in `spawn_empty`, but merged into // the same command for better performance. let index = entity.id().index(); entity.world_scope(|world| { let tick = world.change_tick(); // SAFETY: Entity has been flushed unsafe { world.entities_mut().mark_spawn_despawn(index, caller, tick); } }); entity.insert_with_caller( bundle, InsertMode::Replace, caller, crate::relationship::RelationshipHookMode::Run, ); }); // entity_command::insert(bundle, InsertMode::Replace) entity_commands } /// Returns the [`EntityCommands`] for the given [`Entity`]. /// /// This method does not guarantee that commands queued by the returned `EntityCommands` /// will be successful, since the entity could be despawned before they are executed. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// #[derive(Resource)] /// struct PlayerEntity { /// entity: Entity /// } /// /// #[derive(Component)] /// struct Label(&'static str); /// /// fn example_system(mut commands: Commands, player: Res) { /// // Get the entity and add a component. /// commands.entity(player.entity).insert(Label("hello world")); /// } /// # bevy_ecs::system::assert_is_system(example_system); /// ``` /// /// # See also /// /// - [`get_entity`](Self::get_entity) for the fallible version. #[inline] #[track_caller] pub fn entity(&mut self, entity: Entity) -> EntityCommands { EntityCommands { entity, commands: self.reborrow(), } } /// Returns the [`EntityCommands`] for the requested [`Entity`] if it exists. /// /// This method does not guarantee that commands queued by the returned `EntityCommands` /// will be successful, since the entity could be despawned before they are executed. /// /// # Errors /// /// Returns [`EntityDoesNotExistError`] if the requested entity does not exist. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// #[derive(Resource)] /// struct PlayerEntity { /// entity: Entity /// } /// /// #[derive(Component)] /// struct Label(&'static str); /// /// fn example_system(mut commands: Commands, player: Res) -> Result { /// // Get the entity if it still exists and store the `EntityCommands`. /// // If it doesn't exist, the `?` operator will propagate the returned error /// // to the system, and the system will pass it to an error handler. /// let mut entity_commands = commands.get_entity(player.entity)?; /// /// // Add a component to the entity. /// entity_commands.insert(Label("hello world")); /// /// // Return from the system successfully. /// Ok(()) /// } /// # bevy_ecs::system::assert_is_system(example_system); /// ``` /// /// # See also /// /// - [`entity`](Self::entity) for the infallible version. #[inline] #[track_caller] pub fn get_entity( &mut self, entity: Entity, ) -> Result { if self.entities.contains(entity) { Ok(EntityCommands { entity, commands: self.reborrow(), }) } else { Err(EntityDoesNotExistError::new(entity, self.entities)) } } /// Spawns multiple entities with the same combination of components, /// based on a batch of [`Bundles`](Bundle). /// /// A batch can be any type that implements [`IntoIterator`] and contains bundles, /// such as a [`Vec`](alloc::vec::Vec) or an array `[Bundle; N]`. /// /// This method is equivalent to iterating the batch /// and calling [`spawn`](Self::spawn) for each bundle, /// but is faster by pre-allocating memory and having exclusive [`World`] access. /// /// # Example /// /// ``` /// use bevy_ecs::prelude::*; /// /// #[derive(Component)] /// struct Score(u32); /// /// fn example_system(mut commands: Commands) { /// commands.spawn_batch([ /// (Name::new("Alice"), Score(0)), /// (Name::new("Bob"), Score(0)), /// ]); /// } /// # bevy_ecs::system::assert_is_system(example_system); /// ``` /// /// # See also /// /// - [`spawn`](Self::spawn) to spawn an entity with components. /// - [`spawn_empty`](Self::spawn_empty) to spawn an entity without components. #[track_caller] pub fn spawn_batch(&mut self, batch: I) where I: IntoIterator + Send + Sync + 'static, I::Item: Bundle, { self.queue(command::spawn_batch(batch)); } /// Pushes a generic [`Command`] to the command queue. /// /// If the [`Command`] returns a [`Result`], /// it will be handled using the [default error handler](crate::error::default_error_handler). /// /// To use a custom error handler, see [`Commands::queue_handled`]. /// /// The command can be: /// - A custom struct that implements [`Command`]. /// - A closure or function that matches one of the following signatures: /// - [`(&mut World)`](World) /// - A built-in command from the [`command`] module. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// #[derive(Resource, Default)] /// struct Counter(u64); /// /// struct AddToCounter(String); /// /// impl Command for AddToCounter { /// fn apply(self, world: &mut World) -> Result { /// let mut counter = world.get_resource_or_insert_with(Counter::default); /// let amount: u64 = self.0.parse()?; /// counter.0 += amount; /// Ok(()) /// } /// } /// /// fn add_three_to_counter_system(mut commands: Commands) { /// commands.queue(AddToCounter("3".to_string())); /// } /// /// fn add_twenty_five_to_counter_system(mut commands: Commands) { /// commands.queue(|world: &mut World| { /// let mut counter = world.get_resource_or_insert_with(Counter::default); /// counter.0 += 25; /// }); /// } /// # bevy_ecs::system::assert_is_system(add_three_to_counter_system); /// # bevy_ecs::system::assert_is_system(add_twenty_five_to_counter_system); /// ``` pub fn queue + HandleError, T>(&mut self, command: C) { self.queue_internal(command.handle_error()); } /// Pushes a generic [`Command`] to the command queue. /// /// If the [`Command`] returns a [`Result`], /// the given `error_handler` will be used to handle error cases. /// /// To implicitly use the default error handler, see [`Commands::queue`]. /// /// The command can be: /// - A custom struct that implements [`Command`]. /// - A closure or function that matches one of the following signatures: /// - [`(&mut World)`](World) /// - [`(&mut World)`](World) `->` [`Result`] /// - A built-in command from the [`command`] module. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// use bevy_ecs::error::warn; /// /// #[derive(Resource, Default)] /// struct Counter(u64); /// /// struct AddToCounter(String); /// /// impl Command for AddToCounter { /// fn apply(self, world: &mut World) -> Result { /// let mut counter = world.get_resource_or_insert_with(Counter::default); /// let amount: u64 = self.0.parse()?; /// counter.0 += amount; /// Ok(()) /// } /// } /// /// fn add_three_to_counter_system(mut commands: Commands) { /// commands.queue_handled(AddToCounter("3".to_string()), warn); /// } /// /// fn add_twenty_five_to_counter_system(mut commands: Commands) { /// commands.queue(|world: &mut World| { /// let mut counter = world.get_resource_or_insert_with(Counter::default); /// counter.0 += 25; /// }); /// } /// # bevy_ecs::system::assert_is_system(add_three_to_counter_system); /// # bevy_ecs::system::assert_is_system(add_twenty_five_to_counter_system); /// ``` pub fn queue_handled + HandleError, T>( &mut self, command: C, error_handler: fn(BevyError, ErrorContext), ) { self.queue_internal(command.handle_error_with(error_handler)); } fn queue_internal(&mut self, command: impl Command) { match &mut self.queue { InternalQueue::CommandQueue(queue) => { queue.push(command); } InternalQueue::RawCommandQueue(queue) => { // SAFETY: `RawCommandQueue` is only every constructed in `Commands::new_raw_from_entities` // where the caller of that has ensured that `queue` outlives `self` unsafe { queue.push(command); } } } } /// Pushes a [`Command`] to the queue for creating entities, if needed, /// and for adding a bundle to each entity. /// /// `bundles_iter` is a type that can be converted into an ([`Entity`], [`Bundle`]) iterator /// (it can also be a collection). /// /// When the command is applied, /// for each (`Entity`, `Bundle`) pair in the given `bundles_iter`, /// the `Entity` is spawned, if it does not exist already. /// Then, the `Bundle` is added to the entity. /// /// This method is equivalent to iterating `bundles_iter`, /// calling [`spawn`](Self::spawn) for each bundle, /// and passing it to [`insert`](EntityCommands::insert), /// but it is faster due to memory pre-allocation. /// /// # 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). #[track_caller] #[deprecated( since = "0.16.0", note = "This can cause extreme performance problems when used with lots of arbitrary free entities. See #18054 on GitHub." )] pub fn insert_or_spawn_batch(&mut self, bundles_iter: I) where I: IntoIterator + Send + Sync + 'static, B: Bundle, { let caller = MaybeLocation::caller(); self.queue(move |world: &mut World| { #[expect( deprecated, reason = "This needs to be supported for now, and the outer item is deprecated too." )] if let Err(invalid_entities) = world.insert_or_spawn_batch_with_caller( bundles_iter, caller, ) { error!( "{caller}: Failed to 'insert or spawn' bundle of type {} into the following invalid entities: {:?}", core::any::type_name::(), invalid_entities ); } }); } /// Adds a series of [`Bundles`](Bundle) to each [`Entity`] they are paired with, /// based on a batch of `(Entity, Bundle)` pairs. /// /// A batch can be any type that implements [`IntoIterator`] /// and contains `(Entity, Bundle)` tuples, /// such as a [`Vec<(Entity, Bundle)>`](alloc::vec::Vec) /// or an array `[(Entity, Bundle); N]`. /// /// This will overwrite any pre-existing components shared by the [`Bundle`] type. /// Use [`Commands::insert_batch_if_new`] to keep the pre-existing components instead. /// /// This method is equivalent to iterating the batch /// and calling [`insert`](EntityCommands::insert) for each pair, /// but is faster by caching data that is shared between entities. /// /// # Fallible /// /// This command will fail if any of the given entities do not exist. /// /// It will internally return a [`TryInsertBatchError`](crate::world::error::TryInsertBatchError), /// which will be handled by the [default error handler](crate::error::default_error_handler). #[track_caller] pub fn insert_batch(&mut self, batch: I) where I: IntoIterator + Send + Sync + 'static, B: Bundle, { self.queue(command::insert_batch(batch, InsertMode::Replace)); } /// Adds a series of [`Bundles`](Bundle) to each [`Entity`] they are paired with, /// based on a batch of `(Entity, Bundle)` pairs. /// /// A batch can be any type that implements [`IntoIterator`] /// and contains `(Entity, Bundle)` tuples, /// such as a [`Vec<(Entity, Bundle)>`](alloc::vec::Vec) /// or an array `[(Entity, Bundle); N]`. /// /// This will keep any pre-existing components shared by the [`Bundle`] type /// and discard the new values. /// Use [`Commands::insert_batch`] to overwrite the pre-existing components instead. /// /// This method is equivalent to iterating the batch /// and calling [`insert_if_new`](EntityCommands::insert_if_new) for each pair, /// but is faster by caching data that is shared between entities. /// /// # Fallible /// /// This command will fail if any of the given entities do not exist. /// /// It will internally return a [`TryInsertBatchError`](crate::world::error::TryInsertBatchError), /// which will be handled by the [default error handler](crate::error::default_error_handler). #[track_caller] pub fn insert_batch_if_new(&mut self, batch: I) where I: IntoIterator + Send + Sync + 'static, B: Bundle, { self.queue(command::insert_batch(batch, InsertMode::Keep)); } /// Adds a series of [`Bundles`](Bundle) to each [`Entity`] they are paired with, /// based on a batch of `(Entity, Bundle)` pairs. /// /// A batch can be any type that implements [`IntoIterator`] /// and contains `(Entity, Bundle)` tuples, /// such as a [`Vec<(Entity, Bundle)>`](alloc::vec::Vec) /// or an array `[(Entity, Bundle); N]`. /// /// This will overwrite any pre-existing components shared by the [`Bundle`] type. /// Use [`Commands::try_insert_batch_if_new`] to keep the pre-existing components instead. /// /// This method is equivalent to iterating the batch /// and calling [`insert`](EntityCommands::insert) for each pair, /// but is faster by caching data that is shared between entities. /// /// # Fallible /// /// This command will fail if any of the given entities do not exist. /// /// It will internally return a [`TryInsertBatchError`](crate::world::error::TryInsertBatchError), /// which will be handled by [logging the error at the `warn` level](warn). #[track_caller] pub fn try_insert_batch(&mut self, batch: I) where I: IntoIterator + Send + Sync + 'static, B: Bundle, { self.queue(command::insert_batch(batch, InsertMode::Replace).handle_error_with(warn)); } /// Adds a series of [`Bundles`](Bundle) to each [`Entity`] they are paired with, /// based on a batch of `(Entity, Bundle)` pairs. /// /// A batch can be any type that implements [`IntoIterator`] /// and contains `(Entity, Bundle)` tuples, /// such as a [`Vec<(Entity, Bundle)>`](alloc::vec::Vec) /// or an array `[(Entity, Bundle); N]`. /// /// This will keep any pre-existing components shared by the [`Bundle`] type /// and discard the new values. /// Use [`Commands::try_insert_batch`] to overwrite the pre-existing components instead. /// /// This method is equivalent to iterating the batch /// and calling [`insert_if_new`](EntityCommands::insert_if_new) for each pair, /// but is faster by caching data that is shared between entities. /// /// # Fallible /// /// This command will fail if any of the given entities do not exist. /// /// It will internally return a [`TryInsertBatchError`](crate::world::error::TryInsertBatchError), /// which will be handled by [logging the error at the `warn` level](warn). #[track_caller] pub fn try_insert_batch_if_new(&mut self, batch: I) where I: IntoIterator + Send + Sync + 'static, B: Bundle, { self.queue(command::insert_batch(batch, InsertMode::Keep).handle_error_with(warn)); } /// Inserts a [`Resource`] into the [`World`] with an inferred value. /// /// The inferred value is determined by the [`FromWorld`] trait of the resource. /// Note that any resource with the [`Default`] trait automatically implements [`FromWorld`], /// and those default values will be used. /// /// If the resource already exists when the command is applied, nothing happens. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// #[derive(Resource, Default)] /// struct Scoreboard { /// current_score: u32, /// high_score: u32, /// } /// /// fn initialize_scoreboard(mut commands: Commands) { /// commands.init_resource::(); /// } /// # bevy_ecs::system::assert_is_system(initialize_scoreboard); /// ``` #[track_caller] pub fn init_resource(&mut self) { self.queue(command::init_resource::()); } /// Inserts a [`Resource`] into the [`World`] with a specific value. /// /// This will overwrite any previous value of the same resource type. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// #[derive(Resource)] /// struct Scoreboard { /// current_score: u32, /// high_score: u32, /// } /// /// fn system(mut commands: Commands) { /// commands.insert_resource(Scoreboard { /// current_score: 0, /// high_score: 0, /// }); /// } /// # bevy_ecs::system::assert_is_system(system); /// ``` #[track_caller] pub fn insert_resource(&mut self, resource: R) { self.queue(command::insert_resource(resource)); } /// Removes a [`Resource`] from the [`World`]. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// #[derive(Resource)] /// struct Scoreboard { /// current_score: u32, /// high_score: u32, /// } /// /// fn system(mut commands: Commands) { /// commands.remove_resource::(); /// } /// # bevy_ecs::system::assert_is_system(system); /// ``` pub fn remove_resource(&mut self) { self.queue(command::remove_resource::()); } /// Runs the system corresponding to the given [`SystemId`]. /// Before running a system, it must first be registered via /// [`Commands::register_system`] or [`World::register_system`]. /// /// The system is run in an exclusive and single-threaded way. /// Running slow systems can become a bottleneck. /// /// There is no way to get the output of a system when run as a command, because the /// execution of the system happens later. To get the output of a system, use /// [`World::run_system`] or [`World::run_system_with`] instead of running the system as a command. /// /// # Fallible /// /// This command will fail if the given [`SystemId`] /// does not correspond to a [`System`](crate::system::System). /// /// It will internally return a [`RegisteredSystemError`](crate::system::system_registry::RegisteredSystemError), /// which will be handled by [logging the error at the `warn` level](warn). pub fn run_system(&mut self, id: SystemId) { self.queue(command::run_system(id).handle_error_with(warn)); } /// Runs the system corresponding to the given [`SystemId`] with input. /// Before running a system, it must first be registered via /// [`Commands::register_system`] or [`World::register_system`]. /// /// The system is run in an exclusive and single-threaded way. /// Running slow systems can become a bottleneck. /// /// There is no way to get the output of a system when run as a command, because the /// execution of the system happens later. To get the output of a system, use /// [`World::run_system`] or [`World::run_system_with`] instead of running the system as a command. /// /// # Fallible /// /// This command will fail if the given [`SystemId`] /// does not correspond to a [`System`](crate::system::System). /// /// It will internally return a [`RegisteredSystemError`](crate::system::system_registry::RegisteredSystemError), /// which will be handled by [logging the error at the `warn` level](warn). pub fn run_system_with(&mut self, id: SystemId, input: I::Inner<'static>) where I: SystemInput: Send> + 'static, { self.queue(command::run_system_with(id, input).handle_error_with(warn)); } /// Registers a system and returns its [`SystemId`] so it can later be called by /// [`Commands::run_system`] or [`World::run_system`]. /// /// This is different from adding systems to a [`Schedule`](crate::schedule::Schedule), /// because the [`SystemId`] that is returned can be used anywhere in the [`World`] to run the associated system. /// /// Using a [`Schedule`](crate::schedule::Schedule) is still preferred for most cases /// due to its better performance and ability to run non-conflicting systems simultaneously. /// /// # Note /// /// If the same system is registered more than once, /// each registration will be considered a different system, /// and they will each be given their own [`SystemId`]. /// /// If you want to avoid registering the same system multiple times, /// consider using [`Commands::run_system_cached`] or storing the [`SystemId`] /// in a [`Local`](crate::system::Local). /// /// # Example /// /// ``` /// # use bevy_ecs::{prelude::*, world::CommandQueue, system::SystemId}; /// #[derive(Resource)] /// struct Counter(i32); /// /// fn register_system( /// mut commands: Commands, /// mut local_system: Local>, /// ) { /// if let Some(system) = *local_system { /// commands.run_system(system); /// } else { /// *local_system = Some(commands.register_system(increment_counter)); /// } /// } /// /// fn increment_counter(mut value: ResMut) { /// value.0 += 1; /// } /// /// # let mut world = World::default(); /// # world.insert_resource(Counter(0)); /// # let mut queue_1 = CommandQueue::default(); /// # let systemid = { /// # let mut commands = Commands::new(&mut queue_1, &world); /// # commands.register_system(increment_counter) /// # }; /// # let mut queue_2 = CommandQueue::default(); /// # { /// # let mut commands = Commands::new(&mut queue_2, &world); /// # commands.run_system(systemid); /// # } /// # queue_1.append(&mut queue_2); /// # queue_1.apply(&mut world); /// # assert_eq!(1, world.resource::().0); /// # bevy_ecs::system::assert_is_system(register_system); /// ``` pub fn register_system( &mut self, system: impl IntoSystem + 'static, ) -> SystemId where I: SystemInput + Send + 'static, O: Send + 'static, { let entity = self.spawn_empty().id(); let system = RegisteredSystem::::new(Box::new(IntoSystem::into_system(system))); self.entity(entity).insert(system); SystemId::from_entity(entity) } /// Removes a system previously registered with [`Commands::register_system`] /// or [`World::register_system`]. /// /// After removing a system, the [`SystemId`] becomes invalid /// and attempting to use it afterwards will result in an error. /// Re-adding the removed system will register it with a new `SystemId`. /// /// # Fallible /// /// This command will fail if the given [`SystemId`] /// does not correspond to a [`System`](crate::system::System). /// /// It will internally return a [`RegisteredSystemError`](crate::system::system_registry::RegisteredSystemError), /// which will be handled by [logging the error at the `warn` level](warn). pub fn unregister_system(&mut self, system_id: SystemId) where I: SystemInput + Send + 'static, O: Send + 'static, { self.queue(command::unregister_system(system_id).handle_error_with(warn)); } /// Removes a system previously registered with one of the following: /// - [`Commands::run_system_cached`] /// - [`World::run_system_cached`] /// - [`World::register_system_cached`] /// /// # Fallible /// /// This command will fail if the given system /// is not currently cached in a [`CachedSystemId`](crate::system::CachedSystemId) resource. /// /// It will internally return a [`RegisteredSystemError`](crate::system::system_registry::RegisteredSystemError), /// which will be handled by [logging the error at the `warn` level](warn). pub fn unregister_system_cached(&mut self, system: S) where I: SystemInput + Send + 'static, O: 'static, M: 'static, S: IntoSystem + Send + 'static, { self.queue(command::unregister_system_cached(system).handle_error_with(warn)); } /// Runs a cached system, registering it if necessary. /// /// Unlike [`Commands::run_system`], this method does not require manual registration. /// /// The first time this method is called for a particular system, /// it will register the system and store its [`SystemId`] in a /// [`CachedSystemId`](crate::system::CachedSystemId) resource for later. /// /// If you would rather manage the [`SystemId`] yourself, /// or register multiple copies of the same system, /// use [`Commands::register_system`] instead. /// /// # Limitations /// /// This method only accepts ZST (zero-sized) systems to guarantee that any two systems of /// the same type must be equal. This means that closures that capture the environment, and /// function pointers, are not accepted. /// /// If you want to access values from the environment within a system, /// consider passing them in as inputs via [`Commands::run_system_cached_with`]. /// /// If that's not an option, consider [`Commands::register_system`] instead. pub fn run_system_cached(&mut self, system: S) where M: 'static, S: IntoSystem<(), (), M> + Send + 'static, { self.queue(command::run_system_cached(system).handle_error_with(warn)); } /// Runs a cached system with an input, registering it if necessary. /// /// Unlike [`Commands::run_system_with`], this method does not require manual registration. /// /// The first time this method is called for a particular system, /// it will register the system and store its [`SystemId`] in a /// [`CachedSystemId`](crate::system::CachedSystemId) resource for later. /// /// If you would rather manage the [`SystemId`] yourself, /// or register multiple copies of the same system, /// use [`Commands::register_system`] instead. /// /// # Limitations /// /// This method only accepts ZST (zero-sized) systems to guarantee that any two systems of /// the same type must be equal. This means that closures that capture the environment, and /// function pointers, are not accepted. /// /// If you want to access values from the environment within a system, /// consider passing them in as inputs. /// /// If that's not an option, consider [`Commands::register_system`] instead. pub fn run_system_cached_with(&mut self, system: S, input: I::Inner<'static>) where I: SystemInput: Send> + Send + 'static, M: 'static, S: IntoSystem + Send + 'static, { self.queue(command::run_system_cached_with(system, input).handle_error_with(warn)); } /// Sends a "global" [`Trigger`](crate::observer::Trigger) without any targets. /// /// This will run any [`Observer`] of the given [`Event`] that isn't scoped to specific targets. #[track_caller] pub fn trigger(&mut self, event: impl Event) { self.queue(command::trigger(event)); } /// Sends a [`Trigger`](crate::observer::Trigger) for the given targets. /// /// This will run any [`Observer`] of the given [`Event`] watching those targets. #[track_caller] pub fn trigger_targets( &mut self, event: impl Event, targets: impl TriggerTargets + Send + Sync + 'static, ) { self.queue(command::trigger_targets(event, targets)); } /// Spawns an [`Observer`] and returns the [`EntityCommands`] associated /// with the entity that stores the observer. /// /// **Calling [`observe`](EntityCommands::observe) on the returned /// [`EntityCommands`] will observe the observer itself, which you very /// likely do not want.** pub fn add_observer( &mut self, observer: impl IntoObserverSystem, ) -> EntityCommands { self.spawn(Observer::new(observer)) } /// Sends an arbitrary [`Event`]. /// /// This is a convenience method for sending events /// without requiring an [`EventWriter`](crate::event::EventWriter). /// /// # Performance /// /// Since this is a command, exclusive world access is used, which means that it will not profit from /// system-level parallelism on supported platforms. /// /// If these events are performance-critical or very frequently sent, /// consider using a typed [`EventWriter`](crate::event::EventWriter) instead. #[track_caller] pub fn send_event(&mut self, event: E) -> &mut Self { self.queue(command::send_event(event)); self } /// Runs the schedule corresponding to the given [`ScheduleLabel`]. /// /// Calls [`World::try_run_schedule`](World::try_run_schedule). /// /// # Fallible /// /// This command will fail if the given [`ScheduleLabel`] /// does not correspond to a [`Schedule`](crate::schedule::Schedule). /// /// It will internally return a [`TryRunScheduleError`](crate::world::error::TryRunScheduleError), /// which will be handled by [logging the error at the `warn` level](warn). /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// # use bevy_ecs::schedule::ScheduleLabel; /// # #[derive(Default, Resource)] /// # struct Counter(u32); /// #[derive(ScheduleLabel, Hash, Debug, PartialEq, Eq, Clone, Copy)] /// struct FooSchedule; /// /// # fn foo_system(mut counter: ResMut) { /// # counter.0 += 1; /// # } /// # /// # let mut schedule = Schedule::new(FooSchedule); /// # schedule.add_systems(foo_system); /// # /// # let mut world = World::default(); /// # /// # world.init_resource::(); /// # world.add_schedule(schedule); /// # /// # assert_eq!(world.resource::().0, 0); /// # /// # let mut commands = world.commands(); /// commands.run_schedule(FooSchedule); /// # /// # world.flush(); /// # /// # assert_eq!(world.resource::().0, 1); /// ``` pub fn run_schedule(&mut self, label: impl ScheduleLabel) { self.queue(command::run_schedule(label).handle_error_with(warn)); } } /// A list of commands that will be run to modify an [`Entity`]. /// /// # Note /// /// Most [`Commands`] (and thereby [`EntityCommands`]) are deferred: /// when you call the command, if it requires mutable access to the [`World`] /// (that is, if it removes, adds, or changes something), it's not executed immediately. /// /// Instead, the command is added to a "command queue." /// The command queue is applied later /// when the [`ApplyDeferred`](crate::schedule::ApplyDeferred) system runs. /// Commands are executed one-by-one so that /// each command can have exclusive access to the `World`. /// /// # Fallible /// /// Due to their deferred nature, an entity you're trying to change with an [`EntityCommand`] /// can be despawned by the time the command is executed. /// /// All deferred entity commands will check whether the entity exists at the time of execution /// and will return an error if it doesn't. /// /// # Error handling /// /// An [`EntityCommand`] can return a [`Result`](crate::error::Result), /// which will be passed to an [error handler](crate::error) if the `Result` is an error. /// /// The [default error handler](crate::error::default_error_handler) panics. /// It can be configured by setting the `GLOBAL_ERROR_HANDLER`. /// /// Alternatively, you can customize the error handler for a specific command /// by calling [`EntityCommands::queue_handled`]. /// /// The [`error`](crate::error) module provides some simple error handlers for convenience. pub struct EntityCommands<'a> { pub(crate) entity: Entity, pub(crate) commands: Commands<'a, 'a>, } impl<'a> EntityCommands<'a> { /// Returns the [`Entity`] id of the entity. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// # /// fn my_system(mut commands: Commands) { /// let entity_id = commands.spawn_empty().id(); /// } /// # bevy_ecs::system::assert_is_system(my_system); /// ``` #[inline] #[must_use = "Omit the .id() call if you do not need to store the `Entity` identifier."] pub fn id(&self) -> Entity { self.entity } /// Returns an [`EntityCommands`] with a smaller lifetime. /// /// This is useful if you have `&mut EntityCommands` but you need `EntityCommands`. pub fn reborrow(&mut self) -> EntityCommands { EntityCommands { entity: self.entity, commands: self.commands.reborrow(), } } /// Get an [`EntityEntryCommands`] for the [`Component`] `T`, /// allowing you to modify it or insert it if it isn't already present. /// /// See also [`insert_if_new`](Self::insert_if_new), /// which lets you insert a [`Bundle`] without overwriting it. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// # #[derive(Resource)] /// # struct PlayerEntity { entity: Entity } /// #[derive(Component)] /// struct Level(u32); /// /// fn level_up_system(mut commands: Commands, player: Res) { /// commands /// .entity(player.entity) /// .entry::() /// // Modify the component if it exists. /// .and_modify(|mut lvl| lvl.0 += 1) /// // Otherwise, insert a default value. /// .or_insert(Level(0)); /// } /// # bevy_ecs::system::assert_is_system(level_up_system); /// ``` pub fn entry(&mut self) -> EntityEntryCommands { EntityEntryCommands { entity_commands: self.reborrow(), marker: PhantomData, } } /// Adds a [`Bundle`] of components to the entity. /// /// This will overwrite any previous value(s) of the same component type. /// See [`EntityCommands::insert_if_new`] to keep the old value instead. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// # #[derive(Resource)] /// # struct PlayerEntity { entity: Entity } /// #[derive(Component)] /// struct Health(u32); /// #[derive(Component)] /// struct Strength(u32); /// #[derive(Component)] /// struct Defense(u32); /// /// #[derive(Bundle)] /// struct CombatBundle { /// health: Health, /// strength: Strength, /// } /// /// fn add_combat_stats_system(mut commands: Commands, player: Res) { /// commands /// .entity(player.entity) /// // You can insert individual components: /// .insert(Defense(10)) /// // You can also insert pre-defined bundles of components: /// .insert(CombatBundle { /// health: Health(100), /// strength: Strength(40), /// }) /// // You can also insert tuples of components and bundles. /// // This is equivalent to the calls above: /// .insert(( /// Defense(10), /// CombatBundle { /// health: Health(100), /// strength: Strength(40), /// }, /// )); /// } /// # bevy_ecs::system::assert_is_system(add_combat_stats_system); /// ``` #[track_caller] pub fn insert(&mut self, bundle: impl Bundle) -> &mut Self { self.queue(entity_command::insert(bundle, InsertMode::Replace)) } /// Adds a [`Bundle`] of components to the entity if the predicate returns true. /// /// This is useful for chaining method calls. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// # #[derive(Resource)] /// # struct PlayerEntity { entity: Entity } /// # impl PlayerEntity { fn is_spectator(&self) -> bool { true } } /// #[derive(Component)] /// struct StillLoadingStats; /// #[derive(Component)] /// struct Health(u32); /// /// fn add_health_system(mut commands: Commands, player: Res) { /// commands /// .entity(player.entity) /// .insert_if(Health(10), || !player.is_spectator()) /// .remove::(); /// } /// # bevy_ecs::system::assert_is_system(add_health_system); /// ``` #[track_caller] pub fn insert_if(&mut self, bundle: impl Bundle, condition: F) -> &mut Self where F: FnOnce() -> bool, { if condition() { self.insert(bundle) } else { self } } /// Adds a [`Bundle`] of components to the entity without overwriting. /// /// This is the same as [`EntityCommands::insert`], but in case of duplicate /// components will leave the old values instead of replacing them with new ones. /// /// See also [`entry`](Self::entry), which lets you modify a [`Component`] if it's present, /// as well as initialize it with a default value. #[track_caller] pub fn insert_if_new(&mut self, bundle: impl Bundle) -> &mut Self { self.queue(entity_command::insert(bundle, InsertMode::Keep)) } /// Adds a [`Bundle`] of components to the entity without overwriting if the /// predicate returns true. /// /// This is the same as [`EntityCommands::insert_if`], but in case of duplicate /// components will leave the old values instead of replacing them with new ones. #[track_caller] pub fn insert_if_new_and(&mut self, bundle: impl Bundle, condition: F) -> &mut Self where F: FnOnce() -> bool, { if condition() { self.insert_if_new(bundle) } else { self } } /// Adds a dynamic [`Component`] to the entity. /// /// This will overwrite any previous value(s) of the same component type. /// /// You should prefer to use the typed API [`EntityCommands::insert`] where possible. /// /// # Safety /// /// - [`ComponentId`] must be from the same world as `self`. /// - `T` must have the same layout as the one passed during `component_id` creation. #[track_caller] pub unsafe fn insert_by_id( &mut self, component_id: ComponentId, value: T, ) -> &mut Self { self.queue( // SAFETY: // - `ComponentId` safety is ensured by the caller. // - `T` safety is ensured by the caller. unsafe { entity_command::insert_by_id(component_id, value, InsertMode::Replace) }, ) } /// Adds a dynamic [`Component`] to the entity. /// /// This will overwrite any previous value(s) of the same component type. /// /// You should prefer to use the typed API [`EntityCommands::try_insert`] where possible. /// /// # Note /// /// If the entity does not exist when this command is executed, /// the resulting error will be ignored. /// /// # Safety /// /// - [`ComponentId`] must be from the same world as `self`. /// - `T` must have the same layout as the one passed during `component_id` creation. #[track_caller] pub unsafe fn try_insert_by_id( &mut self, component_id: ComponentId, value: T, ) -> &mut Self { self.queue_handled( // SAFETY: // - `ComponentId` safety is ensured by the caller. // - `T` safety is ensured by the caller. unsafe { entity_command::insert_by_id(component_id, value, InsertMode::Replace) }, ignore, ) } /// Adds a [`Bundle`] of components to the entity. /// /// This will overwrite any previous value(s) of the same component type. /// /// # Note /// /// If the entity does not exist when this command is executed, /// the resulting error will be ignored. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// # #[derive(Resource)] /// # struct PlayerEntity { entity: Entity } /// #[derive(Component)] /// struct Health(u32); /// #[derive(Component)] /// struct Strength(u32); /// #[derive(Component)] /// struct Defense(u32); /// /// #[derive(Bundle)] /// struct CombatBundle { /// health: Health, /// strength: Strength, /// } /// /// fn add_combat_stats_system(mut commands: Commands, player: Res) { /// commands.entity(player.entity) /// // You can insert individual components: /// .try_insert(Defense(10)) /// // You can also insert tuples of components: /// .try_insert(CombatBundle { /// health: Health(100), /// strength: Strength(40), /// }); /// /// // Suppose this occurs in a parallel adjacent system or process. /// commands.entity(player.entity).despawn(); /// /// // This will not panic nor will it add the component. /// commands.entity(player.entity).try_insert(Defense(5)); /// } /// # bevy_ecs::system::assert_is_system(add_combat_stats_system); /// ``` #[track_caller] pub fn try_insert(&mut self, bundle: impl Bundle) -> &mut Self { self.queue_handled(entity_command::insert(bundle, InsertMode::Replace), ignore) } /// Adds a [`Bundle`] of components to the entity if the predicate returns true. /// /// This is useful for chaining method calls. /// /// # Note /// /// If the entity does not exist when this command is executed, /// the resulting error will be ignored. #[track_caller] pub fn try_insert_if(&mut self, bundle: impl Bundle, condition: F) -> &mut Self where F: FnOnce() -> bool, { if condition() { self.try_insert(bundle) } else { self } } /// Adds a [`Bundle`] of components to the entity without overwriting if the /// predicate returns true. /// /// This is the same as [`EntityCommands::try_insert_if`], but in case of duplicate /// components will leave the old values instead of replacing them with new ones. /// /// # Note /// /// If the entity does not exist when this command is executed, /// the resulting error will be ignored. #[track_caller] pub fn try_insert_if_new_and(&mut self, bundle: impl Bundle, condition: F) -> &mut Self where F: FnOnce() -> bool, { if condition() { self.try_insert_if_new(bundle) } else { self } } /// Adds a [`Bundle`] of components to the entity without overwriting. /// /// This is the same as [`EntityCommands::try_insert`], but in case of duplicate /// components will leave the old values instead of replacing them with new ones. /// /// # Note /// /// If the entity does not exist when this command is executed, /// the resulting error will be ignored. #[track_caller] pub fn try_insert_if_new(&mut self, bundle: impl Bundle) -> &mut Self { self.queue_handled(entity_command::insert(bundle, InsertMode::Keep), ignore) } /// Removes a [`Bundle`] of components from the entity. /// /// This will remove all components that intersect with the provided bundle; /// the entity does not need to have all the components in the bundle. /// /// This will emit a warning if the entity does not exist. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// # #[derive(Resource)] /// # struct PlayerEntity { entity: Entity } /// #[derive(Component)] /// struct Health(u32); /// #[derive(Component)] /// struct Strength(u32); /// #[derive(Component)] /// struct Defense(u32); /// /// #[derive(Bundle)] /// struct CombatBundle { /// health: Health, /// strength: Strength, /// } /// /// fn remove_combat_stats_system(mut commands: Commands, player: Res) { /// commands /// .entity(player.entity) /// // You can remove individual components: /// .remove::() /// // You can also remove pre-defined bundles of components: /// .remove::() /// // You can also remove tuples of components and bundles. /// // This is equivalent to the calls above: /// .remove::<(Defense, CombatBundle)>(); /// } /// # bevy_ecs::system::assert_is_system(remove_combat_stats_system); /// ``` #[track_caller] pub fn remove(&mut self) -> &mut Self { self.queue_handled(entity_command::remove::(), warn) } /// Removes a [`Bundle`] of components from the entity. /// /// This will remove all components that intersect with the provided bundle; /// the entity does not need to have all the components in the bundle. /// /// Unlike [`Self::remove`], /// this will not emit a warning if the entity does not exist. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// # #[derive(Resource)] /// # struct PlayerEntity { entity: Entity } /// #[derive(Component)] /// struct Health(u32); /// #[derive(Component)] /// struct Strength(u32); /// #[derive(Component)] /// struct Defense(u32); /// /// #[derive(Bundle)] /// struct CombatBundle { /// health: Health, /// strength: Strength, /// } /// /// fn remove_combat_stats_system(mut commands: Commands, player: Res) { /// commands /// .entity(player.entity) /// // You can remove individual components: /// .try_remove::() /// // You can also remove pre-defined bundles of components: /// .try_remove::() /// // You can also remove tuples of components and bundles. /// // This is equivalent to the calls above: /// .try_remove::<(Defense, CombatBundle)>(); /// } /// # bevy_ecs::system::assert_is_system(remove_combat_stats_system); /// ``` pub fn try_remove(&mut self) -> &mut Self { self.queue_handled(entity_command::remove::(), ignore) } /// Removes a [`Bundle`] of components from the entity, /// and also removes any components required by the components in the bundle. /// /// This will remove all components that intersect with the provided bundle; /// the entity does not need to have all the components in the bundle. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// # #[derive(Resource)] /// # struct PlayerEntity { entity: Entity } /// # /// #[derive(Component)] /// #[require(B)] /// struct A; /// #[derive(Component, Default)] /// struct B; /// /// fn remove_with_requires_system(mut commands: Commands, player: Res) { /// commands /// .entity(player.entity) /// // Removes both A and B from the entity, because B is required by A. /// .remove_with_requires::(); /// } /// # bevy_ecs::system::assert_is_system(remove_with_requires_system); /// ``` #[track_caller] pub fn remove_with_requires(&mut self) -> &mut Self { self.queue(entity_command::remove_with_requires::()) } /// Removes a dynamic [`Component`] from the entity if it exists. /// /// # Panics /// /// Panics if the provided [`ComponentId`] does not exist in the [`World`]. #[track_caller] pub fn remove_by_id(&mut self, component_id: ComponentId) -> &mut Self { self.queue(entity_command::remove_by_id(component_id)) } /// Removes all components associated with the entity. #[track_caller] pub fn clear(&mut self) -> &mut Self { self.queue(entity_command::clear()) } /// Despawns the entity. /// /// This will emit a warning if the entity does not exist. /// /// # Note /// /// This will also despawn the entities in any [`RelationshipTarget`](crate::relationship::RelationshipTarget) /// that is configured to despawn descendants. /// /// For example, this will recursively despawn [`Children`](crate::hierarchy::Children). /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// # #[derive(Resource)] /// # struct CharacterToRemove { entity: Entity } /// # /// fn remove_character_system( /// mut commands: Commands, /// character_to_remove: Res /// ) { /// commands.entity(character_to_remove.entity).despawn(); /// } /// # bevy_ecs::system::assert_is_system(remove_character_system); /// ``` #[track_caller] pub fn despawn(&mut self) { self.queue_handled(entity_command::despawn(), warn); } /// Despawns the provided entity and its descendants. #[deprecated( since = "0.16.0", note = "Use entity.despawn(), which now automatically despawns recursively." )] pub fn despawn_recursive(&mut self) { self.despawn(); } /// Despawns the entity. /// /// Unlike [`Self::despawn`], /// this will not emit a warning if the entity does not exist. /// /// # Note /// /// This will also despawn the entities in any [`RelationshipTarget`](crate::relationship::RelationshipTarget) /// that is configured to despawn descendants. /// /// For example, this will recursively despawn [`Children`](crate::hierarchy::Children). pub fn try_despawn(&mut self) { self.queue_handled(entity_command::despawn(), ignore); } /// Pushes an [`EntityCommand`] to the queue, /// which will get executed for the current [`Entity`]. /// /// The [default error handler](crate::error::default_error_handler) /// will be used to handle error cases. /// Every [`EntityCommand`] checks whether the entity exists at the time of execution /// and returns an error if it does not. /// /// To use a custom error handler, see [`EntityCommands::queue_handled`]. /// /// The command can be: /// - A custom struct that implements [`EntityCommand`]. /// - A closure or function that matches the following signature: /// - [`(EntityWorldMut)`](EntityWorldMut) /// - [`(EntityWorldMut)`](EntityWorldMut) `->` [`Result`] /// - A built-in command from the [`entity_command`] module. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// # fn my_system(mut commands: Commands) { /// commands /// .spawn_empty() /// // Closures with this signature implement `EntityCommand`. /// .queue(|entity: EntityWorldMut| { /// println!("Executed an EntityCommand for {}", entity.id()); /// }); /// # } /// # bevy_ecs::system::assert_is_system(my_system); /// ``` pub fn queue + CommandWithEntity, T, M>( &mut self, command: C, ) -> &mut Self { self.commands.queue(command.with_entity(self.entity)); self } /// Pushes an [`EntityCommand`] to the queue, /// which will get executed for the current [`Entity`]. /// /// The given `error_handler` will be used to handle error cases. /// Every [`EntityCommand`] checks whether the entity exists at the time of execution /// and returns an error if it does not. /// /// To implicitly use the default error handler, see [`EntityCommands::queue`]. /// /// The command can be: /// - A custom struct that implements [`EntityCommand`]. /// - A closure or function that matches the following signature: /// - [`(EntityWorldMut)`](EntityWorldMut) /// - [`(EntityWorldMut)`](EntityWorldMut) `->` [`Result`] /// - A built-in command from the [`entity_command`] module. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// # fn my_system(mut commands: Commands) { /// use bevy_ecs::error::warn; /// /// commands /// .spawn_empty() /// // Closures with this signature implement `EntityCommand`. /// .queue_handled( /// |entity: EntityWorldMut| -> Result { /// let value: usize = "100".parse()?; /// println!("Successfully parsed the value {} for entity {}", value, entity.id()); /// Ok(()) /// }, /// warn /// ); /// # } /// # bevy_ecs::system::assert_is_system(my_system); /// ``` pub fn queue_handled + CommandWithEntity, T, M>( &mut self, command: C, error_handler: fn(BevyError, ErrorContext), ) -> &mut Self { self.commands .queue_handled(command.with_entity(self.entity), error_handler); self } /// Removes all components except the given [`Bundle`] from the entity. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// # #[derive(Resource)] /// # struct PlayerEntity { entity: Entity } /// #[derive(Component)] /// struct Health(u32); /// #[derive(Component)] /// struct Strength(u32); /// #[derive(Component)] /// struct Defense(u32); /// /// #[derive(Bundle)] /// struct CombatBundle { /// health: Health, /// strength: Strength, /// } /// /// fn remove_combat_stats_system(mut commands: Commands, player: Res) { /// commands /// .entity(player.entity) /// // You can retain a pre-defined Bundle of components, /// // with this removing only the Defense component. /// .retain::() /// // You can also retain only a single component. /// .retain::(); /// } /// # bevy_ecs::system::assert_is_system(remove_combat_stats_system); /// ``` #[track_caller] pub fn retain(&mut self) -> &mut Self { self.queue(entity_command::retain::()) } /// Logs the components of the entity at the [`info`](log::info) level. pub fn log_components(&mut self) -> &mut Self { self.queue(entity_command::log_components()) } /// Returns the underlying [`Commands`]. pub fn commands(&mut self) -> Commands { self.commands.reborrow() } /// Returns a mutable reference to the underlying [`Commands`]. pub fn commands_mut(&mut self) -> &mut Commands<'a, 'a> { &mut self.commands } /// Sends a [`Trigger`](crate::observer::Trigger) targeting the entity. /// /// This will run any [`Observer`] of the given [`Event`] watching this entity. #[track_caller] pub fn trigger(&mut self, event: impl Event) -> &mut Self { self.queue(entity_command::trigger(event)) } /// Creates an [`Observer`] listening for events of type `E` targeting this entity. pub fn observe( &mut self, observer: impl IntoObserverSystem, ) -> &mut Self { self.queue(entity_command::observe(observer)) } /// Clones parts of an entity (components, observers, etc.) onto another entity, /// configured through [`EntityClonerBuilder`]. /// /// By default, the other entity will receive all the components of the original that implement /// [`Clone`] or [`Reflect`](bevy_reflect::Reflect). /// /// # Panics /// /// The command will panic when applied if the target entity does not exist. /// /// # Example /// /// Configure through [`EntityClonerBuilder`] as follows: /// ``` /// # use bevy_ecs::prelude::*; /// #[derive(Component, Clone)] /// struct ComponentA(u32); /// #[derive(Component, Clone)] /// struct ComponentB(u32); /// /// fn example_system(mut commands: Commands) { /// // Create an empty entity. /// let target = commands.spawn_empty().id(); /// /// // Create a new entity and keep its EntityCommands. /// let mut entity = commands.spawn((ComponentA(10), ComponentB(20))); /// /// // Clone only ComponentA onto the target. /// entity.clone_with(target, |builder| { /// builder.deny::(); /// }); /// } /// # bevy_ecs::system::assert_is_system(example_system); /// ``` /// /// See [`EntityClonerBuilder`] for more options. pub fn clone_with( &mut self, target: Entity, config: impl FnOnce(&mut EntityClonerBuilder) + Send + Sync + 'static, ) -> &mut Self { self.queue(entity_command::clone_with(target, config)) } /// Spawns a clone of this entity and returns the [`EntityCommands`] of the clone. /// /// The clone will receive all the components of the original that implement /// [`Clone`] or [`Reflect`](bevy_reflect::Reflect). /// /// To configure cloning behavior (such as only cloning certain components), /// use [`EntityCommands::clone_and_spawn_with`]. /// /// # Note /// /// If the original entity does not exist when this command is applied, /// the returned entity will have no components. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// #[derive(Component, Clone)] /// struct ComponentA(u32); /// #[derive(Component, Clone)] /// struct ComponentB(u32); /// /// fn example_system(mut commands: Commands) { /// // Create a new entity and store its EntityCommands. /// let mut entity = commands.spawn((ComponentA(10), ComponentB(20))); /// /// // Create a clone of the first entity. /// let mut entity_clone = entity.clone_and_spawn(); /// } /// # bevy_ecs::system::assert_is_system(example_system); pub fn clone_and_spawn(&mut self) -> EntityCommands<'_> { self.clone_and_spawn_with(|_| {}) } /// Spawns a clone of this entity and allows configuring cloning behavior /// using [`EntityClonerBuilder`], returning the [`EntityCommands`] of the clone. /// /// By default, the clone will receive all the components of the original that implement /// [`Clone`] or [`Reflect`](bevy_reflect::Reflect). /// /// To exclude specific components, use [`EntityClonerBuilder::deny`]. /// To only include specific components, use [`EntityClonerBuilder::deny_all`] /// followed by [`EntityClonerBuilder::allow`]. /// /// See the methods on [`EntityClonerBuilder`] for more options. /// /// # Note /// /// If the original entity does not exist when this command is applied, /// the returned entity will have no components. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// #[derive(Component, Clone)] /// struct ComponentA(u32); /// #[derive(Component, Clone)] /// struct ComponentB(u32); /// /// fn example_system(mut commands: Commands) { /// // Create a new entity and store its EntityCommands. /// let mut entity = commands.spawn((ComponentA(10), ComponentB(20))); /// /// // Create a clone of the first entity, but without ComponentB. /// let mut entity_clone = entity.clone_and_spawn_with(|builder| { /// builder.deny::(); /// }); /// } /// # bevy_ecs::system::assert_is_system(example_system); pub fn clone_and_spawn_with( &mut self, config: impl FnOnce(&mut EntityClonerBuilder) + Send + Sync + 'static, ) -> EntityCommands<'_> { let entity_clone = self.commands().spawn_empty().id(); self.clone_with(entity_clone, config); EntityCommands { commands: self.commands_mut().reborrow(), entity: entity_clone, } } /// Clones the specified components of this entity and inserts them into another entity. /// /// Components can only be cloned if they implement /// [`Clone`] or [`Reflect`](bevy_reflect::Reflect). /// /// # Panics /// /// The command will panic when applied if the target entity does not exist. pub fn clone_components(&mut self, target: Entity) -> &mut Self { self.queue(entity_command::clone_components::(target)) } /// Clones the specified components of this entity and inserts them into another entity, /// then removes the components from this entity. /// /// Components can only be cloned if they implement /// [`Clone`] or [`Reflect`](bevy_reflect::Reflect). /// /// # Panics /// /// The command will panic when applied if the target entity does not exist. pub fn move_components(&mut self, target: Entity) -> &mut Self { self.queue(entity_command::move_components::(target)) } } /// A wrapper around [`EntityCommands`] with convenience methods for working with a specified component type. pub struct EntityEntryCommands<'a, T> { entity_commands: EntityCommands<'a>, marker: PhantomData, } impl<'a, T: Component> EntityEntryCommands<'a, T> { /// Modify the component `T` if it exists, using the function `modify`. pub fn and_modify(&mut self, modify: impl FnOnce(Mut) + Send + Sync + 'static) -> &mut Self { self.entity_commands .queue(move |mut entity: EntityWorldMut| { if let Some(value) = entity.get_mut() { modify(value); } }); self } } impl<'a, T: Component> EntityEntryCommands<'a, T> { /// [Insert](EntityCommands::insert) `default` into this entity, /// if `T` is not already present. #[track_caller] pub fn or_insert(&mut self, default: T) -> &mut Self { self.entity_commands.insert_if_new(default); self } /// [Insert](EntityCommands::insert) `default` into this entity, /// if `T` is not already present. /// /// # Note /// /// If the entity does not exist when this command is executed, /// the resulting error will be ignored. #[track_caller] pub fn or_try_insert(&mut self, default: T) -> &mut Self { self.entity_commands.try_insert_if_new(default); self } /// [Insert](EntityCommands::insert) the value returned from `default` into this entity, /// if `T` is not already present. #[track_caller] pub fn or_insert_with(&mut self, default: impl Fn() -> T) -> &mut Self { self.or_insert(default()) } /// [Insert](EntityCommands::insert) the value returned from `default` into this entity, /// if `T` is not already present. /// /// # Note /// /// If the entity does not exist when this command is executed, /// the resulting error will be ignored. #[track_caller] pub fn or_try_insert_with(&mut self, default: impl Fn() -> T) -> &mut Self { self.or_try_insert(default()) } /// [Insert](EntityCommands::insert) `T::default` into this entity, /// if `T` is not already present. #[track_caller] pub fn or_default(&mut self) -> &mut Self where T: Default, { self.or_insert(T::default()) } /// [Insert](EntityCommands::insert) `T::from_world` into this entity, /// if `T` is not already present. #[track_caller] pub fn or_from_world(&mut self) -> &mut Self where T: FromWorld, { self.entity_commands .queue(entity_command::insert_from_world::(InsertMode::Keep)); self } /// Get the [`EntityCommands`] from which the [`EntityEntryCommands`] was initiated. /// /// This allows you to continue chaining method calls after calling [`EntityCommands::entry`]. /// /// # Example /// /// ``` /// # use bevy_ecs::prelude::*; /// # #[derive(Resource)] /// # struct PlayerEntity { entity: Entity } /// #[derive(Component)] /// struct Level(u32); /// /// fn level_up_system(mut commands: Commands, player: Res) { /// commands /// .entity(player.entity) /// .entry::() /// // Modify the component if it exists. /// .and_modify(|mut lvl| lvl.0 += 1) /// // Otherwise, insert a default value. /// .or_insert(Level(0)) /// // Return the EntityCommands for the entity. /// .entity() /// // Continue chaining method calls. /// .insert(Name::new("Player")); /// } /// # bevy_ecs::system::assert_is_system(level_up_system); /// ``` pub fn entity(&mut self) -> EntityCommands { self.entity_commands.reborrow() } } #[cfg(test)] mod tests { use crate::{ component::Component, resource::Resource, system::Commands, world::{CommandQueue, FromWorld, World}, }; use alloc::{string::String, sync::Arc, vec, vec::Vec}; use core::{ any::TypeId, sync::atomic::{AtomicUsize, Ordering}, }; #[expect( dead_code, reason = "This struct is used to test how `Drop` behavior works in regards to SparseSet storage, and as such is solely a wrapper around `DropCk` to make it use the SparseSet storage. Because of this, the inner field is intentionally never read." )] #[derive(Component)] #[component(storage = "SparseSet")] struct SparseDropCk(DropCk); #[derive(Component)] 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); } } #[derive(Component, Resource)] struct W(T); fn simple_command(world: &mut World) { world.spawn((W(0u32), W(42u64))); } impl FromWorld for W { fn from_world(world: &mut World) -> Self { let v = world.resource::>(); Self("*".repeat(v.0)) } } #[test] fn entity_commands_entry() { let mut world = World::default(); let mut queue = CommandQueue::default(); let mut commands = Commands::new(&mut queue, &world); let entity = commands.spawn_empty().id(); commands .entity(entity) .entry::>() .and_modify(|_| unreachable!()); queue.apply(&mut world); assert!(!world.entity(entity).contains::>()); let mut commands = Commands::new(&mut queue, &world); commands .entity(entity) .entry::>() .or_insert(W(0)) .and_modify(|mut val| { val.0 = 21; }); queue.apply(&mut world); assert_eq!(21, world.get::>(entity).unwrap().0); let mut commands = Commands::new(&mut queue, &world); commands .entity(entity) .entry::>() .and_modify(|_| unreachable!()) .or_insert(W(42)); queue.apply(&mut world); assert_eq!(42, world.get::>(entity).unwrap().0); world.insert_resource(W(5_usize)); let mut commands = Commands::new(&mut queue, &world); commands.entity(entity).entry::>().or_from_world(); queue.apply(&mut world); assert_eq!("*****", &world.get::>(entity).unwrap().0); let mut commands = Commands::new(&mut queue, &world); let id = commands.entity(entity).entry::>().entity().id(); queue.apply(&mut world); assert_eq!(id, entity); } #[test] fn commands() { let mut world = World::default(); let mut command_queue = CommandQueue::default(); let entity = Commands::new(&mut command_queue, &world) .spawn((W(1u32), W(2u64))) .id(); command_queue.apply(&mut world); assert_eq!(world.entities().len(), 1); let results = world .query::<(&W, &W)>() .iter(&world) .map(|(a, b)| (a.0, b.0)) .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::<(&W, &W)>() .iter(&world) .map(|(a, b)| (a.0, b.0)) .collect::>(); assert_eq!(results2, vec![]); // test adding simple (FnOnce) commands { let mut commands = Commands::new(&mut command_queue, &world); // set up a simple command using a closure that adds one additional entity commands.queue(|world: &mut World| { world.spawn((W(42u32), W(0u64))); }); // set up a simple command using a function that adds one additional entity commands.queue(simple_command); } command_queue.apply(&mut world); let results3 = world .query::<(&W, &W)>() .iter(&world) .map(|(a, b)| (a.0, b.0)) .collect::>(); assert_eq!(results3, vec![(42u32, 0u64), (0u32, 42u64)]); } #[test] fn insert_components() { let mut world = World::default(); let mut command_queue1 = CommandQueue::default(); // insert components let entity = Commands::new(&mut command_queue1, &world) .spawn(()) .insert_if(W(1u8), || true) .insert_if(W(2u8), || false) .insert_if_new(W(1u16)) .insert_if_new(W(2u16)) .insert_if_new_and(W(1u32), || false) .insert_if_new_and(W(2u32), || true) .insert_if_new_and(W(3u32), || true) .id(); command_queue1.apply(&mut world); let results = world .query::<(&W, &W, &W)>() .iter(&world) .map(|(a, b, c)| (a.0, b.0, c.0)) .collect::>(); assert_eq!(results, vec![(1u8, 1u16, 2u32)]); // try to insert components after despawning entity // in another command queue Commands::new(&mut command_queue1, &world) .entity(entity) .try_insert_if_new_and(W(1u64), || true); let mut command_queue2 = CommandQueue::default(); Commands::new(&mut command_queue2, &world) .entity(entity) .despawn(); command_queue2.apply(&mut world); command_queue1.apply(&mut world); } #[test] fn remove_components() { let mut world = World::default(); let mut command_queue = CommandQueue::default(); let (dense_dropck, dense_is_dropped) = DropCk::new_pair(); let (sparse_dropck, sparse_is_dropped) = DropCk::new_pair(); let sparse_dropck = SparseDropCk(sparse_dropck); let entity = Commands::new(&mut command_queue, &world) .spawn((W(1u32), W(2u64), dense_dropck, sparse_dropck)) .id(); command_queue.apply(&mut world); let results_before = world .query::<(&W, &W)>() .iter(&world) .map(|(a, b)| (a.0, b.0)) .collect::>(); assert_eq!(results_before, vec![(1u32, 2u64)]); // test component removal Commands::new(&mut command_queue, &world) .entity(entity) .remove::>() .remove::<(W, W, SparseDropCk, 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::<(&W, &W)>() .iter(&world) .map(|(a, b)| (a.0, b.0)) .collect::>(); assert_eq!(results_after, vec![]); let results_after_u64 = world .query::<&W>() .iter(&world) .map(|v| v.0) .collect::>(); assert_eq!(results_after_u64, vec![]); } #[test] fn remove_components_by_id() { let mut world = World::default(); let mut command_queue = CommandQueue::default(); let (dense_dropck, dense_is_dropped) = DropCk::new_pair(); let (sparse_dropck, sparse_is_dropped) = DropCk::new_pair(); let sparse_dropck = SparseDropCk(sparse_dropck); let entity = Commands::new(&mut command_queue, &world) .spawn((W(1u32), W(2u64), dense_dropck, sparse_dropck)) .id(); command_queue.apply(&mut world); let results_before = world .query::<(&W, &W)>() .iter(&world) .map(|(a, b)| (a.0, b.0)) .collect::>(); assert_eq!(results_before, vec![(1u32, 2u64)]); // test component removal Commands::new(&mut command_queue, &world) .entity(entity) .remove_by_id(world.components().get_id(TypeId::of::>()).unwrap()) .remove_by_id(world.components().get_id(TypeId::of::>()).unwrap()) .remove_by_id(world.components().get_id(TypeId::of::()).unwrap()) .remove_by_id( world .components() .get_id(TypeId::of::()) .unwrap(), ); 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::<(&W, &W)>() .iter(&world) .map(|(a, b)| (a.0, b.0)) .collect::>(); assert_eq!(results_after, vec![]); let results_after_u64 = world .query::<&W>() .iter(&world) .map(|v| v.0) .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(W(123i32)); commands.insert_resource(W(456.0f64)); } 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::>()); } #[test] fn remove_component_with_required_components() { #[derive(Component)] #[require(Y)] struct X; #[derive(Component, Default)] struct Y; #[derive(Component)] struct Z; let mut world = World::default(); let mut queue = CommandQueue::default(); let e = { let mut commands = Commands::new(&mut queue, &world); commands.spawn((X, Z)).id() }; queue.apply(&mut world); assert!(world.get::(e).is_some()); assert!(world.get::(e).is_some()); assert!(world.get::(e).is_some()); { let mut commands = Commands::new(&mut queue, &world); commands.entity(e).remove_with_requires::(); } queue.apply(&mut world); assert!(world.get::(e).is_none()); assert!(world.get::(e).is_none()); assert!(world.get::(e).is_some()); } #[test] fn unregister_system_cached_commands() { let mut world = World::default(); let mut queue = CommandQueue::default(); fn nothing() {} let resources = world.iter_resources().count(); let id = world.register_system_cached(nothing); assert_eq!(world.iter_resources().count(), resources + 1); assert!(world.get_entity(id.entity).is_ok()); let mut commands = Commands::new(&mut queue, &world); commands.unregister_system_cached(nothing); queue.apply(&mut world); assert_eq!(world.iter_resources().count(), resources); assert!(world.get_entity(id.entity).is_err()); } fn is_send() {} fn is_sync() {} #[test] fn test_commands_are_send_and_sync() { is_send::(); is_sync::(); } #[test] fn append() { let mut world = World::default(); let mut queue_1 = CommandQueue::default(); { let mut commands = Commands::new(&mut queue_1, &world); commands.insert_resource(W(123i32)); } let mut queue_2 = CommandQueue::default(); { let mut commands = Commands::new(&mut queue_2, &world); commands.insert_resource(W(456.0f64)); } queue_1.append(&mut queue_2); queue_1.apply(&mut world); assert!(world.contains_resource::>()); assert!(world.contains_resource::>()); } }