diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index 512dadff88017..bf9945c347e23 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -680,6 +680,8 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, '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`] instead. + /// /// # Example /// /// ``` @@ -729,6 +731,62 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> { self } + /// Tries to add a [`Bundle`] of components to the entity. + /// + /// This will overwrite any previous value(s) of the same component type. + /// + /// # Note + /// + /// Unlike [`Self::insert`], this will not panic if the associated 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 add_combat_stats_system(mut commands: Commands, player: Res) { + /// commands.entity(player.entity) + /// // You can try_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(); + /// + /// commands.entity(player.entity) + /// // This will not panic nor will it add the component + /// .try_insert(Defense(5)); + /// } + /// # bevy_ecs::system::assert_is_system(add_combat_stats_system); + /// ``` + pub fn try_insert(&mut self, bundle: impl Bundle) -> &mut Self { + self.commands.add(TryInsert { + entity: self.entity, + bundle, + }); + self + } + /// Removes a [`Bundle`] of components from the entity. /// /// See [`EntityWorldMut::remove`](crate::world::EntityWorldMut::remove) for more @@ -966,6 +1024,25 @@ where } } +/// A [`Command`] that attempts to add the components in a [`Bundle`] to an entity. +pub struct TryInsert { + /// The entity to which the components will be added. + pub entity: Entity, + /// The [`Bundle`] containing the components that will be added to the entity. + pub bundle: T, +} + +impl Command for TryInsert +where + T: Bundle + 'static, +{ + fn apply(self, world: &mut World) { + if let Some(mut entity) = world.get_entity_mut(self.entity) { + entity.insert(self.bundle); + } + } +} + /// A [`Command`] 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.