bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
36.4k stars 3.59k forks source link

Fix bubbling of runtime requirements for `#[require(...)]` attribute #16410

Closed Jondolf closed 1 week ago

Jondolf commented 1 week ago

Objective

Fixes #16406.

Currently, the #[require(...)] attribute internally registers component requirements using register_required_components_manual. This is done recursively in a way where every requirement in the "inheritance tree" is added into a flat RequiredComponents hash map with component constructors and inheritance depths stored.

However, this does not consider runtime requirements: if a plugin has already registered C as required by B, and a component A requires B through the macro attribute, spawning an entity with A won't add C. The required_by hash set for C doesn't have A, and the RequiredComponents of A don't have C.

Intuitively, I would've thought that the macro attribute's requirements were always added before runtime requirements, and in that case I believe this shouldn't have been an issue. But the macro requirements are based on Component::register_required_components, which in a lot of cases (I think) is only called after the first time a bundle with the component is inserted. So if a runtime requirement is defined before this (as is often the case, during Plugin::build), the macro may not take it into account.

Solution

Register requirements inherited from the required component in register_required_components_manual_unchecked.

Testing

I added a test, essentially the same as in #16406, and it now passes. I also ran some of the tests in #16409, and they seem to work as expected. All the existing tests for required components pass.