Add BeforeAdd and AfterRemove lifecycle events#22961
Add BeforeAdd and AfterRemove lifecycle events#22961jonas-meyer wants to merge 5 commits intobevyengine:mainfrom
BeforeAdd and AfterRemove lifecycle events#22961Conversation
There was a problem hiding this comment.
Pull request overview
This PR extends bevy_ecs’s component lifecycle by introducing symmetric “component absent” observation points via the new BeforeAdd and AfterRemove lifecycle events, implemented both as component hooks and as observer-triggered events.
Changes:
- Added
BeforeAddandAfterRemovelifecycle event types, event keys, and prelude exports. - Wired new lifecycle triggers into spawn/insert/remove/despawn paths, including new archetype flags and observer caching.
- Expanded and added tests to validate hook/event ordering and inaccessibility semantics.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| crates/bevy_ecs/src/world/mod.rs | Registers new lifecycle event keys during world initialization. |
| crates/bevy_ecs/src/world/entity_access/world_mut.rs | Triggers AfterRemove during despawn after component data drop. |
| crates/bevy_ecs/src/world/deferred_world.rs | Adds DeferredWorld helpers to run before_add / after_remove hooks. |
| crates/bevy_ecs/src/observer/centralized_storage.rs | Adds cached observer buckets and archetype-flag mapping for the new events. |
| crates/bevy_ecs/src/lifecycle.rs | Defines new event types/keys and adds hook registration APIs + documentation updates. |
| crates/bevy_ecs/src/lib.rs | Exports BeforeAdd / AfterRemove in the public prelude. |
| crates/bevy_ecs/src/component/mod.rs | Adds Component::before_add() / Component::after_remove() hook providers and docs. |
| crates/bevy_ecs/src/component/info.rs | Sets new archetype hook flags based on component hook presence. |
| crates/bevy_ecs/src/component/constants.rs | Reserves new constant component indices for lifecycle observer components. |
| crates/bevy_ecs/src/bundle/tests.rs | Extends hook-order tests and adds new tests for new lifecycle semantics. |
| crates/bevy_ecs/src/bundle/spawner.rs | Triggers BeforeAdd during spawn prior to writing component data. |
| crates/bevy_ecs/src/bundle/remove.rs | Triggers AfterRemove after removal archetype move / data drop. |
| crates/bevy_ecs/src/bundle/insert.rs | Triggers BeforeAdd for newly-added components before the archetype move. |
| crates/bevy_ecs/src/archetype.rs | Adds archetype flags and helper methods for new hook/observer presence checks. |
| crates/bevy_ecs/macros/src/component.rs | Extends derive macro parsing/codegen to support before_add and after_remove attributes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
I'm in favor of something here: I really don't think our existing setup is adequate or clear. This PR looks fine at first blush, but I would like to have a proper design effort before moving forward though. |
|
I've written up something here: #20729 (comment) Is this what you had in mind? Happy to move it to an issue as well. |
Objective
BeforeAddandAfterRemovelifecycle events to complete the symmetric lifecycle: BeforeAdd -> Add -> Insert -> Discard -> Remove -> AfterRemoveSolution
Added before_add and after_remove as both component hooks and observer events, following the same patterns as existing lifecycle events:
BeforeAddfires before Add and Insert. During insert, it fires before the archetype move (component data is not yet accessible). During spawn, it fires after data is written but before Add/Insert hooks.AfterRemovefires after Remove. Component data has already been dropped and is not accessible. Fires during both remove() and despawn().Note
BeforeAdd/AfterRemoveare interim names. A future PR will introduce aBefore<E>/After<E>wrapper scheme.Testing
Showcase
Click to view showcase