Hooks/observers for require components should be invoked in a predictable order.
- Dominant language
- Rust
- Stars
- 48.2k
- Forks
- 4.8k
- Avg merge
- 3d 22h
- Merged PRs (30d)
- 161
Description
## What problem does this solve or what need does it fill?
In the current entity spawn process, hooks/observers for components that are added directly are executed in the order they written in code.
However, the hooks/observers of their require components are executed in a completely non-deterministic order.
## What solution would you like?
It might be better to invoke hook/observer according to declaration order of the `Require` components.
## What alternative(s) have you considered?
There's no way to control the execution order of hooks/observers for `require` components.
## Additional context
```rust
use std::fmt::Debug;
use bevy::ecs::{component::Component, lifecycle::HookContext, world::{DeferredWorld, World}};
fn main() {
let mut world = World::default();
world.spawn(ABC);
world.spawn(GFEDCBA);
}
fn print_hook(
world: DeferredWorld,
HookContext { entity, ..}: HookContext,
){
println!("on_add {:?}",world.get::(entity));
}
#[derive(Component, Default, Debug)]
#[component(on_add = print_hook::)]
struct A;
#[derive(Component, Default, Debug)]
#[component(on_add = print_hook::)]
struct B;
#[derive(Component, Default, Debug)]
#[component(on_add = print_hook::)]
struct C;
#[derive(Component, Default, Debug)]
#[component(on_add = print_hook::)]
struct D;
#[derive(Component, Default, Debug)]
#[component(on_add = print_hook::)]
struct E;
#[derive(Component, Default, Debug)]
#[component(on_add = print_hook::)]
struct F;
#[derive(Component, Default, Debug)]
#[component(on_add = print_hook::)]
struct G;
#[derive(Component, Default, Debug)]
#[component(on_add = print_hook::)]
#[require(A,B,C)]
struct ABC;
#[derive(Component, Default, Debug)]
#[component(on_add = print_hook::)]
#[require(G,F,E,D,C,B,A)]
struct GFEDCBA;
```
output:
``` shell
on_add Some(ABC)
on_add Some(B)
on_add Some(C)
on_add Some(A)
on_add Some(GFEDCBA)
on_add Some(E)
on_add Some(B)
on_add Some(F)
on_add Some(C)
on_add Some(D)
on_add Some(G)
on_add Some(A)
```
https://github.com/bevyengine/bevy/blob/1fb5a622973fb5850c4b85f293fe25d1de06040a/crates/bevy_ecs/src/bundle.rs#L543-L555
The reason is that `BundleInfo::component_ids` gets required component IDs from `RequiredComponents`, which internally uses a `HashMap` for storage.
I'm not sure if this is a bug, so I'm posting issue here.
Contributor guide
Assessment
This issue has not been assessed yet.