diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index 4fb880592ab80..9086ece263824 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -550,7 +550,16 @@ impl<'w, 's> Commands<'w, 's> { I: IntoIterator + Send + Sync + 'static, I::Item: Bundle, { - self.queue(spawn_batch(bundles_iter)); + #[cfg(feature = "track_change_detection")] + let caller = Location::caller(); + self.queue(move |world: &mut World| { + SpawnBatchIter::new( + world, + bundles_iter.into_iter(), + #[cfg(feature = "track_change_detection")] + caller, + ); + }); } /// Pushes a generic [`Command`] to the command queue. @@ -627,7 +636,21 @@ impl<'w, 's> Commands<'w, 's> { I: IntoIterator + Send + Sync + 'static, B: Bundle, { - self.queue(insert_or_spawn_batch(bundles_iter)); + #[cfg(feature = "track_change_detection")] + let caller = Location::caller(); + self.queue(move |world: &mut World| { + if let Err(invalid_entities) = world.insert_or_spawn_batch_with_caller( + bundles_iter, + #[cfg(feature = "track_change_detection")] + caller, + ) { + error!( + "Failed to 'insert or spawn' bundle of type {} into the following invalid entities: {:?}", + core::any::type_name::(), + invalid_entities + ); + } + }); } /// Pushes a [`Command`] to the queue for adding a [`Bundle`] type to a batch of [`Entities`](Entity). @@ -654,7 +677,7 @@ impl<'w, 's> Commands<'w, 's> { I: IntoIterator + Send + Sync + 'static, B: Bundle, { - self.queue(insert_batch(batch)); + self.queue(insert_batch(batch, InsertMode::Replace)); } /// Pushes a [`Command`] to the queue for adding a [`Bundle`] type to a batch of [`Entities`](Entity). @@ -681,7 +704,7 @@ impl<'w, 's> Commands<'w, 's> { I: IntoIterator + Send + Sync + 'static, B: Bundle, { - self.queue(insert_batch_if_new(batch)); + self.queue(insert_batch(batch, InsertMode::Keep)); } /// Pushes a [`Command`] to the queue for adding a [`Bundle`] type to a batch of [`Entities`](Entity). @@ -706,7 +729,7 @@ impl<'w, 's> Commands<'w, 's> { I: IntoIterator + Send + Sync + 'static, B: Bundle, { - self.queue(try_insert_batch(batch)); + self.queue(try_insert_batch(batch, InsertMode::Replace)); } /// Pushes a [`Command`] to the queue for adding a [`Bundle`] type to a batch of [`Entities`](Entity). @@ -731,7 +754,7 @@ impl<'w, 's> Commands<'w, 's> { I: IntoIterator + Send + Sync + 'static, B: Bundle, { - self.queue(try_insert_batch_if_new(batch)); + self.queue(try_insert_batch(batch, InsertMode::Keep)); } /// Pushes a [`Command`] to the queue for inserting a [`Resource`] in the [`World`] with an inferred value. @@ -760,7 +783,9 @@ impl<'w, 's> Commands<'w, 's> { /// ``` #[track_caller] pub fn init_resource(&mut self) { - self.queue(init_resource::); + self.queue(move |world: &mut World| { + world.init_resource::(); + }); } /// Pushes a [`Command`] to the queue for inserting a [`Resource`] in the [`World`] with a specific value. @@ -790,7 +815,15 @@ impl<'w, 's> Commands<'w, 's> { /// ``` #[track_caller] pub fn insert_resource(&mut self, resource: R) { - self.queue(insert_resource(resource)); + #[cfg(feature = "track_change_detection")] + let caller = Location::caller(); + self.queue(move |world: &mut World| { + world.insert_resource_with_caller( + resource, + #[cfg(feature = "track_change_detection")] + caller, + ); + }); } /// Pushes a [`Command`] to the queue for removing a [`Resource`] from the [`World`]. @@ -814,7 +847,9 @@ impl<'w, 's> Commands<'w, 's> { /// # bevy_ecs::system::assert_is_system(system); /// ``` pub fn remove_resource(&mut self) { - self.queue(remove_resource::); + self.queue(move |world: &mut World| { + world.remove_resource::(); + }); } /// Runs the system corresponding to the given [`SystemId`]. @@ -1289,7 +1324,7 @@ impl<'a> EntityCommands<'a> { F: FnOnce() -> bool, { if condition() { - self.queue(insert(bundle, InsertMode::Replace)) + self.insert(bundle) } else { self } @@ -1309,6 +1344,7 @@ impl<'a> EntityCommands<'a> { /// The command will panic when applied if the associated entity does not exist. /// /// To avoid a panic in this case, use the command [`Self::try_insert_if_new`] instead. + #[track_caller] pub fn insert_if_new(&mut self, bundle: impl Bundle) -> &mut Self { self.queue(insert(bundle, InsertMode::Keep)) } @@ -1327,6 +1363,7 @@ impl<'a> EntityCommands<'a> { /// /// To avoid a panic in this case, use the command [`Self::try_insert_if_new`] /// instead. + #[track_caller] pub fn insert_if_new_and(&mut self, bundle: impl Bundle, condition: F) -> &mut Self where F: FnOnce() -> bool, @@ -1359,10 +1396,18 @@ impl<'a> EntityCommands<'a> { value: T, ) -> &mut Self { let caller = Location::caller(); - // SAFETY: same invariants as parent call - self.queue(unsafe {insert_by_id(component_id, value, move |world, entity| { - panic!("error[B0003]: {caller}: Could not insert a component {component_id:?} (with type {}) for entity {entity:?}, which {}. See: https://bevyengine.org/learn/errors/b0003", core::any::type_name::(), world.entities().entity_does_not_exist_error_details_message(entity)); - })}) + self.queue(move |entity: Entity, world: &mut World| { + if let Ok(mut entity) = world.get_entity_mut(entity) { + // SAFETY: + // - `component_id` safety is ensured by the caller + // - `ptr` is valid within the `make` block + OwningPtr::make(value, |ptr| unsafe { + entity.insert_by_id(component_id, ptr); + }); + } else { + panic!("error[B0003]: {caller}: Could not insert a component {component_id:?} (with type {}) for entity {entity:?}, which {}. See: https://bevyengine.org/learn/errors/b0003", core::any::type_name::(), world.entities().entity_does_not_exist_error_details_message(entity)); + } + }) } /// Attempts to add a dynamic component to an entity. @@ -1373,13 +1418,22 @@ impl<'a> EntityCommands<'a> { /// /// - [`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 { - // SAFETY: same invariants as parent call - self.queue(unsafe { insert_by_id(component_id, value, |_, _| {}) }) + self.queue(move |entity: Entity, world: &mut World| { + if let Ok(mut entity) = world.get_entity_mut(entity) { + // SAFETY: + // - `component_id` safety is ensured by the caller + // - `ptr` is valid within the `make` block + OwningPtr::make(value, |ptr| unsafe { + entity.insert_by_id(component_id, ptr); + }); + } + }) } /// Tries to add a [`Bundle`] of components to the entity. @@ -1467,7 +1521,7 @@ impl<'a> EntityCommands<'a> { F: FnOnce() -> bool, { if condition() { - self.queue(try_insert(bundle, InsertMode::Replace)) + self.try_insert(bundle) } else { self } @@ -1508,6 +1562,7 @@ impl<'a> EntityCommands<'a> { /// } /// # bevy_ecs::system::assert_is_system(add_health_system); /// ``` + #[track_caller] pub fn try_insert_if_new_and(&mut self, bundle: impl Bundle, condition: F) -> &mut Self where F: FnOnce() -> bool, @@ -1528,6 +1583,7 @@ impl<'a> EntityCommands<'a> { /// # Note /// /// Unlike [`Self::insert_if_new`], this will not panic if the associated entity does not exist. + #[track_caller] pub fn try_insert_if_new(&mut self, bundle: impl Bundle) -> &mut Self { self.queue(try_insert(bundle, InsertMode::Keep)) } @@ -1571,7 +1627,11 @@ impl<'a> EntityCommands<'a> { where T: Bundle, { - self.queue(remove::) + self.queue(move |entity: Entity, world: &mut World| { + if let Ok(mut entity) = world.get_entity_mut(entity) { + entity.remove::(); + } + }) } /// Removes all components in the [`Bundle`] components and remove all required components for each component in the [`Bundle`] from entity. @@ -1599,17 +1659,33 @@ impl<'a> EntityCommands<'a> { /// # bevy_ecs::system::assert_is_system(remove_with_requires_system); /// ``` pub fn remove_with_requires(&mut self) -> &mut Self { - self.queue(remove_with_requires::) + self.queue(move |entity: Entity, world: &mut World| { + if let Ok(mut entity) = world.get_entity_mut(entity) { + entity.remove_with_requires::(); + } + }) } - /// Removes a component from the entity. + /// Removes a dynamic [`Component`] from the entity if it exists. + /// + /// # Panics + /// + /// Panics if the provided [`ComponentId`] does not exist in the [`World`]. pub fn remove_by_id(&mut self, component_id: ComponentId) -> &mut Self { - self.queue(remove_by_id(component_id)) + self.queue(move |entity: Entity, world: &mut World| { + if let Ok(mut entity) = world.get_entity_mut(entity) { + entity.remove_by_id(component_id); + } + }) } /// Removes all components associated with the entity. pub fn clear(&mut self) -> &mut Self { - self.queue(clear()) + self.queue(move |entity: Entity, world: &mut World| { + if let Ok(mut entity) = world.get_entity_mut(entity) { + entity.clear(); + } + }) } /// Despawns the entity. @@ -1641,7 +1717,7 @@ impl<'a> EntityCommands<'a> { /// ``` #[track_caller] pub fn despawn(&mut self) { - self.queue(despawn()); + self.queue(despawn(true)); } /// Despawns the entity. @@ -1649,7 +1725,7 @@ impl<'a> EntityCommands<'a> { /// the same function as [`Self::despawn`] without emitting warnings. #[track_caller] pub fn try_despawn(&mut self) { - self.queue(try_despawn()); + self.queue(despawn(false)); } /// Pushes an [`EntityCommand`] to the queue, which will get executed for the current [`Entity`]. @@ -1714,7 +1790,11 @@ impl<'a> EntityCommands<'a> { where T: Bundle, { - self.queue(retain::) + self.queue(move |entity: Entity, world: &mut World| { + if let Ok(mut entity) = world.get_entity_mut(entity) { + entity.retain::(); + } + }) } /// Logs the components of the entity at the info level. @@ -1723,7 +1803,13 @@ impl<'a> EntityCommands<'a> { /// /// The command will panic when applied if the associated entity does not exist. pub fn log_components(&mut self) -> &mut Self { - self.queue(log_components) + self.queue(move |entity: Entity, world: &mut World| { + let debug_infos: Vec<_> = world + .inspect_entity(entity) + .map(ComponentInfo::name) + .collect(); + info!("Entity {entity}: {debug_infos:?}"); + }) } /// Returns the underlying [`Commands`]. @@ -1748,9 +1834,13 @@ impl<'a> EntityCommands<'a> { /// Creates an [`Observer`] listening for a trigger of type `T` that targets this entity. pub fn observe( &mut self, - system: impl IntoObserverSystem, + observer: impl IntoObserverSystem, ) -> &mut Self { - self.queue(observe(system)) + self.queue(move |entity: Entity, world: &mut World| { + if let Ok(mut entity) = world.get_entity_mut(entity) { + entity.observe(observer); + } + }) } /// Clones parts of an entity (components, observers, etc.) onto another entity, @@ -1759,6 +1849,12 @@ impl<'a> EntityCommands<'a> { /// 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 [`EntityCloneBuilder`] as follows: /// ``` /// # use bevy_ecs::prelude::*; @@ -1787,16 +1883,16 @@ impl<'a> EntityCommands<'a> { /// - [`EntityCloneBuilder`] /// - [`CloneEntityWithObserversExt`](crate::observer::CloneEntityWithObserversExt) /// - `CloneEntityHierarchyExt` - /// - /// # Panics - /// - /// The command will panic when applied if either of the entities do not exist. pub fn clone_with( &mut self, target: Entity, config: impl FnOnce(&mut EntityCloneBuilder) + Send + Sync + 'static, ) -> &mut Self { - self.queue(clone_with(target, config)) + self.queue(move |entity: Entity, world: &mut World| { + if let Ok(mut entity) = world.get_entity_mut(entity) { + entity.clone_with(target, config); + } + }) } /// Spawns a clone of this entity and returns the [`EntityCommands`] of the clone. @@ -1807,9 +1903,10 @@ impl<'a> EntityCommands<'a> { /// To configure cloning behavior (such as only cloning certain components), /// use [`EntityCommands::clone_and_spawn_with`]. /// - /// # Panics + /// # Note /// - /// The command will panic when applied if the original entity does not exist. + /// If the original entity does not exist when this command is applied, + /// the returned entity will have no components. /// /// # Example /// @@ -1845,9 +1942,10 @@ impl<'a> EntityCommands<'a> { /// /// See the methods on [`EntityCloneBuilder`] for more options. /// - /// # Panics + /// # Note /// - /// The command will panic when applied if the original entity does not exist. + /// If the original entity does not exist when this command is applied, + /// the returned entity will have no components. /// /// # Example /// @@ -1874,7 +1972,7 @@ impl<'a> EntityCommands<'a> { config: impl FnOnce(&mut EntityCloneBuilder) + Send + Sync + 'static, ) -> EntityCommands<'_> { let entity_clone = self.commands().spawn_empty().id(); - self.queue(clone_with(entity_clone, config)); + self.clone_with(entity_clone, config); EntityCommands { commands: self.commands_mut().reborrow(), entity: entity_clone, @@ -1888,9 +1986,13 @@ impl<'a> EntityCommands<'a> { /// /// # Panics /// - /// The command will panic when applied if either of the entities do not exist. + /// 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(clone_components::(target)) + self.queue(move |entity: Entity, world: &mut World| { + if let Ok(mut entity) = world.get_entity_mut(entity) { + entity.clone_components::(target); + } + }) } /// Clones the specified components of this entity and inserts them into another entity, @@ -1901,9 +2003,13 @@ impl<'a> EntityCommands<'a> { /// /// # Panics /// - /// The command will panic when applied if either of the entities do not exist. + /// 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(move_components::(target)) + self.queue(move |entity: Entity, world: &mut World| { + if let Ok(mut entity) = world.get_entity_mut(entity) { + entity.move_components::(target); + } + }) } } @@ -1937,8 +2043,7 @@ impl<'a, T: Component> EntityEntryCommands<'a, T> { /// See [`or_try_insert`](Self::or_try_insert) for a non-panicking version. #[track_caller] pub fn or_insert(&mut self, default: T) -> &mut Self { - self.entity_commands - .queue(insert(default, InsertMode::Keep)); + self.entity_commands.insert_if_new(default); self } @@ -1949,8 +2054,7 @@ impl<'a, T: Component> EntityEntryCommands<'a, T> { /// See also [`or_insert_with`](Self::or_insert_with). #[track_caller] pub fn or_try_insert(&mut self, default: T) -> &mut Self { - self.entity_commands - .queue(try_insert(default, InsertMode::Keep)); + self.entity_commands.try_insert_if_new(default); self } @@ -1989,8 +2093,6 @@ impl<'a, T: Component> EntityEntryCommands<'a, T> { where T: Default, { - #[allow(clippy::unwrap_or_default)] - // FIXME: use `expect` once stable self.or_insert(T::default()) } @@ -2006,8 +2108,20 @@ impl<'a, T: Component> EntityEntryCommands<'a, T> { where T: FromWorld, { - self.entity_commands - .queue(insert_from_world::(InsertMode::Keep)); + let caller = Location::caller(); + self.entity_commands.queue(move |entity: Entity, world: &mut World| { + let value = T::from_world(world); + if let Ok(mut entity) = world.get_entity_mut(entity) { + entity.insert_with_caller( + value, + InsertMode::Keep, + #[cfg(feature = "track_change_detection")] + caller, + ); + } else { + panic!("error[B0003]: {caller}: Could not insert a bundle (of type `{}`) for {entity:?}, which {}. See: https://bevyengine.org/learn/errors/b0003", core::any::type_name::(), world.entities().entity_does_not_exist_error_details_message(entity) ); + } + }); self } } @@ -2039,82 +2153,12 @@ where } } -/// A [`Command`] that consumes an iterator of [`Bundle`]s to spawn a series of entities. -/// -/// This is more efficient than spawning the entities individually. -#[track_caller] -fn spawn_batch(bundles_iter: I) -> impl Command -where - I: IntoIterator + Send + Sync + 'static, - B: Bundle, -{ - #[cfg(feature = "track_change_detection")] - let caller = Location::caller(); - move |world: &mut World| { - SpawnBatchIter::new( - world, - bundles_iter.into_iter(), - #[cfg(feature = "track_change_detection")] - caller, - ); - } -} - -/// A [`Command`] that consumes an iterator to add a series of [`Bundle`]s to a set of entities. -/// If any entities do not already exist in the world, they will be spawned. -/// -/// This is more efficient than inserting the bundles individually. -#[track_caller] -fn insert_or_spawn_batch(bundles_iter: I) -> impl Command -where - I: IntoIterator + Send + Sync + 'static, - B: Bundle, -{ - #[cfg(feature = "track_change_detection")] - let caller = Location::caller(); - move |world: &mut World| { - if let Err(invalid_entities) = world.insert_or_spawn_batch_with_caller( - bundles_iter, - #[cfg(feature = "track_change_detection")] - caller, - ) { - error!( - "Failed to 'insert or spawn' bundle of type {} into the following invalid entities: {:?}", - core::any::type_name::(), - invalid_entities - ); - } - } -} - -/// A [`Command`] that consumes an iterator to add a series of [`Bundles`](Bundle) to a set of entities. -/// If any entities do not exist in the world, this command will panic. -/// -/// This is more efficient than inserting the bundles individually. -#[track_caller] -fn insert_batch(batch: I) -> impl Command -where - I: IntoIterator + Send + Sync + 'static, - B: Bundle, -{ - #[cfg(feature = "track_change_detection")] - let caller = Location::caller(); - move |world: &mut World| { - world.insert_batch_with_caller( - batch, - InsertMode::Replace, - #[cfg(feature = "track_change_detection")] - caller, - ); - } -} - /// A [`Command`] that consumes an iterator to add a series of [`Bundles`](Bundle) to a set of entities. /// If any entities do not exist in the world, this command will panic. /// /// This is more efficient than inserting the bundles individually. #[track_caller] -fn insert_batch_if_new(batch: I) -> impl Command +fn insert_batch(batch: I, mode: InsertMode) -> impl Command where I: IntoIterator + Send + Sync + 'static, B: Bundle, @@ -2124,29 +2168,7 @@ where move |world: &mut World| { world.insert_batch_with_caller( batch, - InsertMode::Keep, - #[cfg(feature = "track_change_detection")] - caller, - ); - } -} - -/// A [`Command`] that consumes an iterator to add a series of [`Bundles`](Bundle) to a set of entities. -/// If any entities do not exist in the world, this command will ignore them. -/// -/// This is more efficient than inserting the bundles individually. -#[track_caller] -fn try_insert_batch(batch: I) -> impl Command -where - I: IntoIterator + Send + Sync + 'static, - B: Bundle, -{ - #[cfg(feature = "track_change_detection")] - let caller = Location::caller(); - move |world: &mut World| { - world.try_insert_batch_with_caller( - batch, - InsertMode::Replace, + mode, #[cfg(feature = "track_change_detection")] caller, ); @@ -2158,7 +2180,7 @@ where /// /// This is more efficient than inserting the bundles individually. #[track_caller] -fn try_insert_batch_if_new(batch: I) -> impl Command +fn try_insert_batch(batch: I, mode: InsertMode) -> impl Command where I: IntoIterator + Send + Sync + 'static, B: Bundle, @@ -2168,7 +2190,7 @@ where move |world: &mut World| { world.try_insert_batch_with_caller( batch, - InsertMode::Keep, + mode, #[cfg(feature = "track_change_detection")] caller, ); @@ -2183,25 +2205,10 @@ where /// This won't clean up external references to the entity (such as parent-child relationships /// if you're using `bevy_hierarchy`), which may leave the world in an invalid state. #[track_caller] -fn despawn() -> impl EntityCommand { +fn despawn(log_warning: bool) -> impl EntityCommand { let caller = Location::caller(); move |entity: Entity, world: &mut World| { - world.despawn_with_caller(entity, caller, true); - } -} - -/// A [`Command`] that despawns a specific entity. -/// This will not emit a warning if the entity does not exist. -/// -/// # Note -/// -/// This won't clean up external references to the entity (such as parent-child relationships -/// if you're using `bevy_hierarchy`), which may leave the world in an invalid state. -#[track_caller] -fn try_despawn() -> impl EntityCommand { - let caller = Location::caller(); - move |entity: Entity, world: &mut World| { - world.despawn_with_caller(entity, caller, false); + world.despawn_with_caller(entity, caller, log_warning); } } @@ -2223,25 +2230,6 @@ fn insert(bundle: T, mode: InsertMode) -> impl EntityCommand { } } -/// An [`EntityCommand`] that adds the component using its `FromWorld` implementation. -#[track_caller] -fn insert_from_world(mode: InsertMode) -> impl EntityCommand { - let caller = Location::caller(); - move |entity: Entity, world: &mut World| { - let value = T::from_world(world); - if let Ok(mut entity) = world.get_entity_mut(entity) { - entity.insert_with_caller( - value, - mode, - #[cfg(feature = "track_change_detection")] - caller, - ); - } else { - panic!("error[B0003]: {caller}: Could not insert a bundle (of type `{}`) for {entity:?}, which {}. See: https://bevyengine.org/learn/errors/b0003", core::any::type_name::(), world.entities().entity_does_not_exist_error_details_message(entity) ); - } - } -} - /// An [`EntityCommand`] that attempts to add the components in a [`Bundle`] to an entity. /// Does nothing if the entity does not exist. #[track_caller] @@ -2260,156 +2248,6 @@ fn try_insert(bundle: impl Bundle, mode: InsertMode) -> impl EntityCommand { } } -/// An [`EntityCommand`] that attempts to add the dynamic component to an entity. -/// -/// # Safety -/// -/// - The returned `EntityCommand` must be queued for the world where `component_id` was created. -/// - `T` must be the type represented by `component_id`. -unsafe fn insert_by_id( - component_id: ComponentId, - value: T, - on_none_entity: impl FnOnce(&mut World, Entity) + Send + 'static, -) -> impl EntityCommand { - move |entity: Entity, world: &mut World| { - if let Ok(mut entity) = world.get_entity_mut(entity) { - // SAFETY: - // - `component_id` safety is ensured by the caller - // - `ptr` is valid within the `make` block; - OwningPtr::make(value, |ptr| unsafe { - entity.insert_by_id(component_id, ptr); - }); - } else { - on_none_entity(world, entity); - } - } -} - -/// An [`EntityCommand`] that removes components from an entity. -/// -/// For a [`Bundle`] type `T`, this will remove any components in the bundle. -/// Any components in the bundle that aren't found on the entity will be ignored. -fn remove(entity: Entity, world: &mut World) { - if let Ok(mut entity) = world.get_entity_mut(entity) { - entity.remove::(); - } -} - -/// An [`EntityCommand`] that removes components with a provided [`ComponentId`] from an entity. -/// # Panics -/// -/// Panics if the provided [`ComponentId`] does not exist in the [`World`]. -fn remove_by_id(component_id: ComponentId) -> impl EntityCommand { - move |entity: Entity, world: &mut World| { - if let Ok(mut entity) = world.get_entity_mut(entity) { - entity.remove_by_id(component_id); - } - } -} - -/// An [`EntityCommand`] that remove all components in the bundle and remove all required components for each component in the bundle. -fn remove_with_requires(entity: Entity, world: &mut World) { - if let Ok(mut entity) = world.get_entity_mut(entity) { - entity.remove_with_requires::(); - } -} - -/// An [`EntityCommand`] that removes all components associated with a provided entity. -fn clear() -> impl EntityCommand { - move |entity: Entity, world: &mut World| { - if let Ok(mut entity) = world.get_entity_mut(entity) { - entity.clear(); - } - } -} - -/// An [`EntityCommand`] that removes components from an entity. -/// -/// For a [`Bundle`] type `T`, this will remove all components except those in the bundle. -/// Any components in the bundle that aren't found on the entity will be ignored. -fn retain(entity: Entity, world: &mut World) { - if let Ok(mut entity_mut) = world.get_entity_mut(entity) { - entity_mut.retain::(); - } -} - -/// A [`Command`] that inserts a [`Resource`] into the world using a value -/// created with the [`FromWorld`] trait. -#[track_caller] -fn init_resource(world: &mut World) { - world.init_resource::(); -} - -/// A [`Command`] that removes the [resource](Resource) `R` from the world. -#[track_caller] -fn remove_resource(world: &mut World) { - world.remove_resource::(); -} - -/// A [`Command`] that inserts a [`Resource`] into the world. -#[track_caller] -fn insert_resource(resource: R) -> impl Command { - #[cfg(feature = "track_change_detection")] - let caller = Location::caller(); - move |world: &mut World| { - world.insert_resource_with_caller( - resource, - #[cfg(feature = "track_change_detection")] - caller, - ); - } -} - -/// [`EntityCommand`] to log the components of a given entity. See [`EntityCommands::log_components`]. -fn log_components(entity: Entity, world: &mut World) { - let debug_infos: Vec<_> = world - .inspect_entity(entity) - .map(ComponentInfo::name) - .collect(); - info!("Entity {entity}: {debug_infos:?}"); -} - -fn observe( - observer: impl IntoObserverSystem, -) -> impl EntityCommand { - move |entity: Entity, world: &mut World| { - if let Ok(mut entity) = world.get_entity_mut(entity) { - entity.observe(observer); - } - } -} - -/// An [`EntityCommand`] that clones an entity with configurable cloning behavior. -fn clone_with( - target: Entity, - config: impl FnOnce(&mut EntityCloneBuilder) + Send + Sync + 'static, -) -> impl EntityCommand { - move |entity: Entity, world: &mut World| { - if let Ok(mut entity) = world.get_entity_mut(entity) { - entity.clone_with(target, config); - } - } -} - -/// An [`EntityCommand`] that clones the specified components into another entity. -fn clone_components(target: Entity) -> impl EntityCommand { - move |entity: Entity, world: &mut World| { - if let Ok(mut entity) = world.get_entity_mut(entity) { - entity.clone_components::(target); - } - } -} - -/// An [`EntityCommand`] that clones the specified components into another entity -/// and removes them from the original entity. -fn move_components(target: Entity) -> impl EntityCommand { - move |entity: Entity, world: &mut World| { - if let Ok(mut entity) = world.get_entity_mut(entity) { - entity.move_components::(target); - } - } -} - #[cfg(test)] #[allow(clippy::float_cmp, clippy::approx_constant)] mod tests {