bevy/crates/bevy_ecs/src
Guillaume Wafo-Tapa 6eb6afeb2d
Spawn batch with relationship (#19519)
# Objective

Fixes #19356
Issue: Spawning a batch of entities in relationship with the same target
adds the relationship between the target and only the last entity of the
batch. `spawn_batch` flushes only after having spawned all entities.
This means each spawned entity will have run the `on_insert` hook of its
`Relationship` component. Here is the relevant part of that hook:
```Rust
            if let Some(mut relationship_target) =
                target_entity_mut.get_mut::<Self::RelationshipTarget>()
            {
                relationship_target.collection_mut_risky().add(entity);
            } else {
                let mut target = <Self::RelationshipTarget as RelationshipTarget>::with_capacity(1);
                target.collection_mut_risky().add(entity);
                world.commands().entity(target_entity).insert(target);
            }
```
Given the above snippet and since there's no flush between spawns, each
entity finds the target without a `RelationshipTarget` component and
defers the insertion of that component with the entity's id as the sole
member of its collection. When the commands are finally flushed, each
insertion after the first replaces the one before and in the process
triggers the `on_replace` hook of `RelationshipTarget` which removes the
`Relationship` component from the corresponding entity. That's how we
end up in the invalid state.

## Solution

I see two possible solutions
1. Flush after every spawn
2. Defer the whole code snippet above

I don't know enough about bevy as a whole but 2. seems much more
efficient to me. This is what I'm proposing here. I have a doubt though
because I've started to look at #19348 that 1. would fix as well.

## Testing

I added a test for the issue. I've put it in `relationship/mod.rs` but I
could see it in `world/spawn_batch.rs` or `lib.rs` because the test is
as much about `spawn_batch` as it is about relationships.
2025-06-30 22:13:38 +00:00
..
entity Split EntityClonerBuilder in OptOut and OptIn variants (#19649) 2025-06-24 00:12:08 +00:00
error Don't create errors for ignored failed commands (#19718) 2025-06-29 16:34:20 +00:00
event Event Split: Event, EntityEvent, and BufferedEvent (#19647) 2025-06-15 16:46:34 +00:00
observer Split EntityClonerBuilder in OptOut and OptIn variants (#19649) 2025-06-24 00:12:08 +00:00
query Add newlines before impl blocks (#19746) 2025-06-22 23:07:02 +00:00
reflect ECS: put strings only used for debug behind a feature (#19558) 2025-06-18 20:15:25 +00:00
relationship Spawn batch with relationship (#19519) 2025-06-30 22:13:38 +00:00
schedule Upgrade to Rust 1.88 (#19825) 2025-06-26 19:38:19 +00:00
storage bevy_ecs: remove use of needless_return (#19859) 2025-06-29 17:12:33 +00:00
system Don't create errors for ignored failed commands (#19718) 2025-06-29 16:34:20 +00:00
world Split EntityClonerBuilder in OptOut and OptIn variants (#19649) 2025-06-24 00:12:08 +00:00
archetype.rs Add newlines before impl blocks (#19746) 2025-06-22 23:07:02 +00:00
batching.rs Nonmax all rows (#19132) 2025-05-26 17:39:55 +00:00
bundle.rs Refactor bundle derive (#19749) 2025-06-20 16:36:08 +00:00
change_detection.rs Event Split: Event, EntityEvent, and BufferedEvent (#19647) 2025-06-15 16:46:34 +00:00
component.rs Let Component::map_entities defer to MapEntities (#19414) 2025-06-23 21:05:04 +00:00
entity_disabling.rs bevy_reflect: Add clone registrations project-wide (#18307) 2025-03-17 18:32:35 +00:00
hierarchy.rs Fix some typos (#19788) 2025-06-23 22:32:46 +00:00
intern.rs Rename bevy_platform_support to bevy_platform (#18813) 2025-04-11 23:13:28 +00:00
label.rs Remove upcasting methods + Cleanup interned label code (#18984) 2025-05-26 15:38:12 +00:00
lib.rs Rename num_entities to entity_count (#19781) 2025-06-23 05:08:02 +00:00
lifecycle.rs Added clone bounds to EntityEvents that were missing them. (#19708) 2025-06-17 21:22:32 +00:00
name.rs Add newlines before impl blocks (#19746) 2025-06-22 23:07:02 +00:00
never.rs Use never_say_never hack to work around Rust 2024 regression for fn traits (#18804) 2025-04-14 19:59:48 +00:00
resource.rs refactor(utils): move SyncCell and SyncUnsafeCell to bevy_platform (#19305) 2025-05-27 04:57:26 +00:00
spawn.rs Add newlines before impl blocks (#19746) 2025-06-22 23:07:02 +00:00
traversal.rs Let query items borrow from query state to avoid needing to clone (#15396) 2025-06-16 21:05:41 +00:00