From b1c1aac1b3f01b2f40f6140a35ed414fbeae1b11 Mon Sep 17 00:00:00 2001 From: Eagster <79881080+ElliottjPierce@users.noreply.github.com> Date: Tue, 25 Mar 2025 15:19:53 -0400 Subject: [PATCH] Ensure spawning related entities in an OnAdd observer downstream of a World::spawn in a Command does not cause a crash (#18545) # Objective fixes #18452. ## Solution Spawning used to flush commands only, but those commands can reserve entities. Now, spawning flushes everything, including reserved entities. I checked, and this was the only place where `flush_commands` is used instead of `flush` by mistake. ## Testing I simplified the MRE from #18452 into its own test, which fails on main, but passes on this branch. --- crates/bevy_ecs/src/observer/mod.rs | 17 +++++++++++++++++ crates/bevy_ecs/src/world/mod.rs | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/observer/mod.rs b/crates/bevy_ecs/src/observer/mod.rs index 4bbd82c85b..21c4e10697 100644 --- a/crates/bevy_ecs/src/observer/mod.rs +++ b/crates/bevy_ecs/src/observer/mod.rs @@ -1648,6 +1648,23 @@ mod tests { assert_eq!(vec!["event", "event"], world.resource::().0); } + // Originally for https://github.com/bevyengine/bevy/issues/18452 + #[test] + fn observer_modifies_relationship() { + fn on_add(trigger: Trigger, mut commands: Commands) { + commands + .entity(trigger.target()) + .with_related::(|rsc| { + rsc.spawn_empty(); + }); + } + + let mut world = World::new(); + world.add_observer(on_add); + world.spawn(A); + world.flush(); + } + // Regression test for https://github.com/bevyengine/bevy/issues/14467 // Fails prior to https://github.com/bevyengine/bevy/pull/15398 #[test] diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index f9f8828015..5f2da150c7 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -1174,7 +1174,7 @@ impl World { // SAFETY: command_queue is not referenced anywhere else if !unsafe { self.command_queue.is_empty() } { - self.flush_commands(); + self.flush(); entity_location = self .entities() .get(entity)