From 772524b3a682619a5241a65ce979ce9308615427 Mon Sep 17 00:00:00 2001 From: Freyja-moth <156322843+Freyja-moth@users.noreply.github.com> Date: Wed, 9 Apr 2025 03:34:49 +0100 Subject: [PATCH] Change with_related to work with a Bundle and added with_relationships method (#18699) # Objective Fixes #18678 ## Solution Moved the current `with_related` method to `with_relationships` and added a new `with_related` that uses a bundle. I'm not entirely sold on the name just yet, if anyone has any ideas let me know. ## Testing I wasn't able to test these changes because it crashed my computer every time I tried (fun). But there don't seem to be any tests that use the old `with_related` method so it should be fine, hopefully ## Showcase ```rust commands.spawn_empty() .with_related::(Name::new("Related thingy")) .with_relationships(|rel| { rel.spawn(Name::new("Second related thingy")); }); ``` --------- Co-authored-by: Carter Anderson --- crates/bevy_ecs/src/hierarchy.rs | 7 +++---- crates/bevy_ecs/src/observer/mod.rs | 2 +- .../src/relationship/related_methods.rs | 20 +++++++++++++++++-- crates/bevy_ecs/src/spawn.rs | 6 ++---- examples/ecs/relationships.rs | 8 +++++--- 5 files changed, 29 insertions(+), 14 deletions(-) diff --git a/crates/bevy_ecs/src/hierarchy.rs b/crates/bevy_ecs/src/hierarchy.rs index da92d5babb..91b1cc78cb 100644 --- a/crates/bevy_ecs/src/hierarchy.rs +++ b/crates/bevy_ecs/src/hierarchy.rs @@ -268,7 +268,7 @@ impl<'w> EntityWorldMut<'w> { /// Spawns children of this entity (with a [`ChildOf`] relationship) by taking a function that operates on a [`ChildSpawner`]. /// See also [`with_related`](Self::with_related). pub fn with_children(&mut self, func: impl FnOnce(&mut ChildSpawner)) -> &mut Self { - self.with_related(func); + self.with_related_entities(func); self } @@ -352,7 +352,7 @@ impl<'a> EntityCommands<'a> { &mut self, func: impl FnOnce(&mut RelatedSpawnerCommands), ) -> &mut Self { - self.with_related(func); + self.with_related_entities(func); self } @@ -406,8 +406,7 @@ impl<'a> EntityCommands<'a> { /// /// [`with_children`]: EntityCommands::with_children pub fn with_child(&mut self, bundle: impl Bundle) -> &mut Self { - let parent = self.id(); - self.commands.spawn((bundle, ChildOf(parent))); + self.with_related::(bundle); self } diff --git a/crates/bevy_ecs/src/observer/mod.rs b/crates/bevy_ecs/src/observer/mod.rs index 53e499c652..774538937e 100644 --- a/crates/bevy_ecs/src/observer/mod.rs +++ b/crates/bevy_ecs/src/observer/mod.rs @@ -1654,7 +1654,7 @@ mod tests { fn on_add(trigger: Trigger, mut commands: Commands) { commands .entity(trigger.target()) - .with_related::(|rsc| { + .with_related_entities::(|rsc| { rsc.spawn_empty(); }); } diff --git a/crates/bevy_ecs/src/relationship/related_methods.rs b/crates/bevy_ecs/src/relationship/related_methods.rs index f48335c83b..5a6019fa61 100644 --- a/crates/bevy_ecs/src/relationship/related_methods.rs +++ b/crates/bevy_ecs/src/relationship/related_methods.rs @@ -13,8 +13,17 @@ use core::{marker::PhantomData, mem}; use super::OrderedRelationshipSourceCollection; impl<'w> EntityWorldMut<'w> { + /// Spawns a entity related to this entity (with the `R` relationship) by taking a bundle + pub fn with_related(&mut self, bundle: impl Bundle) -> &mut Self { + let parent = self.id(); + self.world_scope(|world| { + world.spawn((bundle, R::from(parent))); + }); + self + } + /// Spawns entities related to this entity (with the `R` relationship) by taking a function that operates on a [`RelatedSpawner`]. - pub fn with_related( + pub fn with_related_entities( &mut self, func: impl FnOnce(&mut RelatedSpawner), ) -> &mut Self { @@ -322,8 +331,15 @@ impl<'w> EntityWorldMut<'w> { } impl<'a> EntityCommands<'a> { + /// Spawns a entity related to this entity (with the `R` relationship) by taking a bundle + pub fn with_related(&mut self, bundle: impl Bundle) -> &mut Self { + let parent = self.id(); + self.commands.spawn((bundle, R::from(parent))); + self + } + /// Spawns entities related to this entity (with the `R` relationship) by taking a function that operates on a [`RelatedSpawner`]. - pub fn with_related( + pub fn with_related_entities( &mut self, func: impl FnOnce(&mut RelatedSpawnerCommands), ) -> &mut Self { diff --git a/crates/bevy_ecs/src/spawn.rs b/crates/bevy_ecs/src/spawn.rs index f9bb94ea0e..5235889ffb 100644 --- a/crates/bevy_ecs/src/spawn.rs +++ b/crates/bevy_ecs/src/spawn.rs @@ -125,7 +125,7 @@ impl) + Send + Sync + 'static> for SpawnWith { fn spawn(self, world: &mut World, entity: Entity) { - world.entity_mut(entity).with_related(self.0); + world.entity_mut(entity).with_related_entities(self.0); } fn size_hint(&self) -> usize { @@ -235,9 +235,7 @@ pub struct SpawnOneRelated { impl BundleEffect for SpawnOneRelated { fn apply(self, entity: &mut EntityWorldMut) { - entity.with_related::(|s| { - s.spawn(self.bundle); - }); + entity.with_related::(self.bundle); } } diff --git a/examples/ecs/relationships.rs b/examples/ecs/relationships.rs index 955c1fe35e..13542974c8 100644 --- a/examples/ecs/relationships.rs +++ b/examples/ecs/relationships.rs @@ -53,12 +53,14 @@ fn main() { // Relations are just components, so we can add them into the bundle that we're spawning. let bob = commands.spawn((Name::new("Bob"), Targeting(alice))).id(); - // The `with_related` helper method on `EntityCommands` can be used to add relations in a more ergonomic way. + // The `with_related` and `with_relationships` helper methods on `EntityCommands` can be used to add relations in a more ergonomic way. let charlie = commands .spawn((Name::new("Charlie"), Targeting(bob))) - // The `with_related` method will automatically add the `Targeting` component to any entities spawned within the closure, + // The `with_related` method will spawn a bundle with `Targeting` relationship + .with_related::(Name::new("James")) + // The `with_relationships` method will automatically add the `Targeting` component to any entities spawned within the closure, // targeting the entity that we're calling `with_related` on. - .with_related::(|related_spawner_commands| { + .with_related_entities::(|related_spawner_commands| { // We could spawn multiple entities here, and they would all target `charlie`. related_spawner_commands.spawn(Name::new("Devon")); })