mirror of
https://github.com/bevyengine/bevy
synced 2024-11-21 12:13:25 +00:00
Fix runtime required components not registering correctly (#16436)
# Objective - Fixes #16406 - Fixes an issue where registering a "deeper" required component, then a "shallower" required component, would result in the wrong required constructor being used for the root component. ## Solution - Make `register_required_components` add any "parent" of a component as `required_by` to the new "child". - Assign the depth of the `requiree` plus 1 as the depth of a new runtime required component. ## Testing - Added two new tests.
This commit is contained in:
parent
9c2a2668d2
commit
29f7572f2a
2 changed files with 62 additions and 3 deletions
|
@ -1065,6 +1065,10 @@ impl Components {
|
||||||
|
|
||||||
// Propagate the new required components up the chain to all components that require the requiree.
|
// Propagate the new required components up the chain to all components that require the requiree.
|
||||||
if let Some(required_by) = self.get_required_by(requiree).cloned() {
|
if let Some(required_by) = self.get_required_by(requiree).cloned() {
|
||||||
|
// `required` is now required by anything that `requiree` was required by.
|
||||||
|
self.get_required_by_mut(required)
|
||||||
|
.unwrap()
|
||||||
|
.extend(required_by.iter().copied());
|
||||||
for &required_by_id in required_by.iter() {
|
for &required_by_id in required_by.iter() {
|
||||||
// SAFETY: The component is in the list of required components, so it must exist already.
|
// SAFETY: The component is in the list of required components, so it must exist already.
|
||||||
let required_components = unsafe {
|
let required_components = unsafe {
|
||||||
|
@ -1072,9 +1076,10 @@ impl Components {
|
||||||
.debug_checked_unwrap()
|
.debug_checked_unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Register the original required component for the requiree.
|
// Register the original required component in the "parent" of the requiree.
|
||||||
// The inheritance depth is `1` since this is a component required by the original requiree.
|
// The inheritance depth is 1 deeper than the `requiree` wrt `required_by_id`.
|
||||||
required_components.register_by_id(required, constructor, 1);
|
let depth = required_components.0.get(&requiree).expect("requiree is required by required_by_id, so its required_components must include requiree").inheritance_depth;
|
||||||
|
required_components.register_by_id(required, constructor, depth + 1);
|
||||||
|
|
||||||
for (component_id, component) in inherited_requirements.iter() {
|
for (component_id, component) in inherited_requirements.iter() {
|
||||||
// Register the required component.
|
// Register the required component.
|
||||||
|
|
|
@ -2345,6 +2345,60 @@ mod tests {
|
||||||
assert!(world.entity(id).get::<C>().is_some());
|
assert!(world.entity(id).get::<C>().is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn runtime_required_components_propagate_up_even_more() {
|
||||||
|
#[derive(Component)]
|
||||||
|
struct A;
|
||||||
|
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
struct B;
|
||||||
|
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
struct C;
|
||||||
|
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
struct D;
|
||||||
|
|
||||||
|
let mut world = World::new();
|
||||||
|
|
||||||
|
world.register_required_components::<A, B>();
|
||||||
|
world.register_required_components::<B, C>();
|
||||||
|
world.register_required_components::<C, D>();
|
||||||
|
|
||||||
|
let id = world.spawn(A).id();
|
||||||
|
|
||||||
|
assert!(world.entity(id).get::<D>().is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn runtime_required_components_deep_require_does_not_override_shallow_require() {
|
||||||
|
#[derive(Component)]
|
||||||
|
struct A;
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
struct B;
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
struct C;
|
||||||
|
#[derive(Component)]
|
||||||
|
struct Counter(i32);
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
struct D;
|
||||||
|
|
||||||
|
let mut world = World::new();
|
||||||
|
|
||||||
|
world.register_required_components::<A, B>();
|
||||||
|
world.register_required_components::<B, C>();
|
||||||
|
world.register_required_components::<C, D>();
|
||||||
|
world.register_required_components_with::<D, Counter>(|| Counter(2));
|
||||||
|
// This should replace the require constructor in A since it is
|
||||||
|
// shallower.
|
||||||
|
world.register_required_components_with::<C, Counter>(|| Counter(1));
|
||||||
|
|
||||||
|
let id = world.spawn(A).id();
|
||||||
|
|
||||||
|
// The "shallower" of the two components is used.
|
||||||
|
assert_eq!(world.entity(id).get::<Counter>().unwrap().0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn runtime_required_components_existing_archetype() {
|
fn runtime_required_components_existing_archetype() {
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
|
|
Loading…
Reference in a new issue