diff --git a/crates/bevy_ecs/src/component.rs b/crates/bevy_ecs/src/component.rs index e2712dcb7b2fb..dcd8b4c8c32b5 100644 --- a/crates/bevy_ecs/src/component.rs +++ b/crates/bevy_ecs/src/component.rs @@ -2113,7 +2113,7 @@ impl RequiredComponents { unsafe { self.register_dynamic(component_id, erased, inheritance_depth) }; } - /// Iterates the ids of all required components. This includes recursive required components. + /// Iterates the ids of all required components' ids. This includes recursive required components. pub fn iter_ids(&self) -> impl Iterator + '_ { self.0.keys().copied() } @@ -2131,8 +2131,21 @@ impl RequiredComponents { // Merges `required_components` into this collection. This only inserts a required component // if it _did not already exist_. pub(crate) fn merge(&mut self, required_components: &RequiredComponents) { - for (id, constructor) in &required_components.0 { - self.0.entry(*id).or_insert_with(|| constructor.clone()); + for ( + component_id, + RequiredComponent { + constructor, + inheritance_depth, + }, + ) in required_components + .0 + .iter() + .map(|(id, req)| (*id, req.clone())) + { + // SAFETY: This exact registration must have been done on `required_components`, so safety is ensured by that caller. + unsafe { + self.register_dynamic(component_id, constructor, inheritance_depth); + } } } } diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index 8d415d7469183..429dea5090a93 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -2635,6 +2635,37 @@ mod tests { assert_eq!(to_vec(required_z), vec![(b, 0), (c, 1)]); } + #[test] + fn required_components_inheritance_depth_bias() { + #[derive(Component, PartialEq, Eq, Clone, Copy, Debug)] + struct MyRequired(bool); + + #[derive(Component, Default)] + #[require(MyRequired(|| MyRequired(false)))] + struct MiddleMan; + + #[derive(Component, Default)] + #[require(MiddleMan)] + struct ConflictingRequire; + + #[derive(Component, Default)] + #[require(MyRequired(|| MyRequired(true)))] + struct MyComponent; + + let mut world = World::new(); + let order_a = world + .spawn((ConflictingRequire, MyComponent)) + .get::() + .cloned(); + let order_b = world + .spawn((MyComponent, ConflictingRequire)) + .get::() + .cloned(); + + assert_eq!(order_a, Some(MyRequired(true))); + assert_eq!(order_b, Some(MyRequired(true))); + } + #[test] #[should_panic = "Recursive required components detected: A → B → C → B\nhelp: If this is intentional, consider merging the components."] fn required_components_recursion_errors() {