From 9167f02bdf71280eec0034d6dfd30d25cceaecca Mon Sep 17 00:00:00 2001 From: Olle Lukowski Date: Sat, 26 Apr 2025 14:32:02 -0700 Subject: [PATCH] Create `EntityCommands::remove_if` (#18899) # Objective Fixes #18857. ## Solution Add the requested method, and a `try_` variant as well. ## Testing It compiles, doctests succeed, and is trivial enough that I don't think it needs a unit test (correct me if I'm wrong though). --- crates/bevy_ecs/src/system/commands/mod.rs | 57 ++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index 4cb6d61bc0..7f0d7d84de 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -1618,6 +1618,63 @@ impl<'a> EntityCommands<'a> { self.queue_handled(entity_command::remove::(), warn) } + /// Removes a [`Bundle`] of components from 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 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) + /// .remove_if::<(Defense, CombatBundle)>(|| !player.is_spectator()); + /// } + /// # bevy_ecs::system::assert_is_system(remove_combat_stats_system); + /// ``` + #[track_caller] + pub fn remove_if(&mut self, condition: impl FnOnce() -> bool) -> &mut Self { + if condition() { + self.remove::() + } else { + self + } + } + + /// Removes a [`Bundle`] of components from 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_remove_if(&mut self, condition: impl FnOnce() -> bool) -> &mut Self { + if condition() { + self.try_remove::() + } else { + self + } + } + /// Removes a [`Bundle`] of components from the entity. /// /// This will remove all components that intersect with the provided bundle;