Skip to content

Commit ea0cd7d

Browse files
authored
Merge branch 'main' into main
2 parents ad27472 + 0d620cd commit ea0cd7d

3 files changed

Lines changed: 169 additions & 20 deletions

File tree

crates/bevy_core_widgets/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "bevy_core_widgets"
33
version = "0.16.0-dev"
44
edition = "2024"
5-
description = "Unstyled common widgets for B Bevy Engine"
5+
description = "Unstyled common widgets for Bevy Engine"
66
homepage = "https://bevyengine.org"
77
repository = "https://github.com/bevyengine/bevy"
88
license = "MIT OR Apache-2.0"

crates/bevy_ecs/src/observer/mod.rs

Lines changed: 167 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,136 @@
1-
//! Types for creating and storing [`Observer`]s
1+
//! Observers are a push-based tool for responding to [`Event`]s.
2+
//!
3+
//! ## Observer targeting
4+
//!
5+
//! Observers can be "global", listening for events that are both targeted at and not targeted at any specific entity,
6+
//! or they can be "entity-specific", listening for events that are targeted at specific entities.
7+
//!
8+
//! They can also be further refined by listening to events targeted at specific components
9+
//! (instead of using a generic event type), as is done with the [`OnAdd`] family of lifecycle events.
10+
//!
11+
//! When entities are observed, they will receive an [`ObservedBy`] component,
12+
//! which will be updated to track the observers that are currently observing them.
13+
//!
14+
//! Currently, [observers cannot be retargeted after spawning](https://github.com/bevyengine/bevy/issues/19587):
15+
//! despawn and respawn an observer as a workaround.
16+
//!
17+
//! ## Writing observers
18+
//!
19+
//! Observers are systems which implement [`IntoObserverSystem`] that listen for [`Event`]s matching their
20+
//! type and target(s).
21+
//! To write observer systems, use the [`Trigger`] system parameter as the first parameter of your system.
22+
//! This parameter provides access to the specific event that triggered the observer,
23+
//! as well as the entity that the event was targeted at, if any.
24+
//!
25+
//! Observers can request other data from the world,
26+
//! such as via a [`Query`] or [`Res`]. Commonly, you might want to verify that
27+
//! the entity that the observable event is targeting has a specific component,
28+
//! or meets some other condition.
29+
//! [`Query::get`] or [`Query::contains`] on the [`Trigger::target`] entity
30+
//! is a good way to do this.
31+
//!
32+
//! [`Commands`] can also be used inside of observers.
33+
//! This can be particularly useful for triggering other observers!
34+
//!
35+
//! ## Spawning observers
36+
//!
37+
//! Observers can be spawned via [`World::add_observer`], or the equivalent app method.
38+
//! This will cause an entity with the [`Observer`] component to be created,
39+
//! which will then run the observer system whenever the event it is watching is triggered.
40+
//!
41+
//! You can control the targets that an observer is watching by calling [`Observer::watch_entity`]
42+
//! once the entity is spawned, or by manually spawning an entity with the [`Observer`] component
43+
//! configured with the desired targets.
44+
//!
45+
//! Observers are fundamentally defined as "entities which have the [`Observer`] component"
46+
//! allowing you to add it manually to existing entities.
47+
//! At first, this seems convenient, but only one observer can be added to an entity at a time,
48+
//! regardless of the event it responds to: like always, components are unique.
49+
//!
50+
//! Instead, a better way to achieve a similar aim is to
51+
//! use the [`EntityWorldMut::observe`] / [`EntityCommands::observe`] method,
52+
//! which spawns a new observer, and configures it to watch the entity it is called on.
53+
//! Unfortunately, observers defined in this way
54+
//! [currently cannot be spawned as part of bundles](https://github.com/bevyengine/bevy/issues/14204).
55+
//!
56+
//! ## Triggering observers
57+
//!
58+
//! Observers are most commonly triggered by [`Commands`],
59+
//! via [`Commands::trigger`] (for untargeted events) or [`Commands::trigger_targets`] (for targeted events).
60+
//! Like usual, equivalent methods are available on [`World`], allowing you to reduce overhead when working with exclusive world access.
61+
//!
62+
//! If your observer is configured to watch for a specific component or set of components instead,
63+
//! you can pass in [`ComponentId`]s into [`Commands::trigger_targets`] by using the [`TriggerTargets`] trait.
64+
//! As discussed in the [`Trigger`] documentation, this use case is rare, and is currently only used
65+
//! for [lifecycle](crate::lifecycle) events, which are automatically emitted.
66+
//!
67+
//! ## Observer bubbling
68+
//!
69+
//! When events are targeted at an entity, they can optionally bubble to other targets,
70+
//! typically up to parents in an entity hierarchy.
71+
//!
72+
//! This behavior is controlled via [`Event::Traversal`] and [`Event::AUTO_PROPAGATE`],
73+
//! with the details of the propagation path specified by the [`Traversal`](crate::traversal::Traversal) trait.
74+
//!
75+
//! When auto-propagation is enabled, propagaion must be manually stopped to prevent the event from
76+
//! continuing to other targets.
77+
//! This can be done using the [`Trigger::propagate`] method on the [`Trigger`] system parameter inside of your observer.
78+
//!
79+
//! ## Observer timing
80+
//!
81+
//! Observers are triggered via [`Commands`], which imply that they are evaluated at the next sync point in the ECS schedule.
82+
//! Accordingly, they have full access to the world, and are evaluated sequentially, in the order that the commands were sent.
83+
//!
84+
//! To control the relative ordering of observers sent from different systems,
85+
//! order the systems in the schedule relative to each other.
86+
//!
87+
//! Currently, Bevy does not provide [a way to specify the ordering of observers](https://github.com/bevyengine/bevy/issues/14890)
88+
//! listening to the same event relative to each other.
89+
//!
90+
//! Commands sent by observers are [currently not immediately applied](https://github.com/bevyengine/bevy/issues/19569).
91+
//! Instead, all queued observers will run, and then all of the commands from those observers will be applied.
92+
//! Careful use of [`Schedule::apply_deferred`] may help as a workaround.
93+
//!
94+
//! ## Lifecycle events and observers
95+
//!
96+
//! It is important to note that observers, just like [hooks](crate::lifecycle::ComponentHooks),
97+
//! can listen to and respond to [lifecycle](crate::lifecycle) events.
98+
//! Unlike hooks, observers are not treated as an "innate" part of component behavior:
99+
//! they can be added or removed at runtime, and multiple observers
100+
//! can be registered for the same lifecycle event for the same component.
101+
//!
102+
//! The ordering of hooks versus observers differs based on the lifecycle event in question:
103+
//!
104+
//! - when adding components, hooks are evaluated first, then observers
105+
//! - when removing components, observers are evaluated first, then hooks
106+
//!
107+
//! This allows hooks to act as constructors and destructors for components,
108+
//! as they always have the first and final say in the component's lifecycle.
109+
//!
110+
//! ## Cleaning up observers
111+
//!
112+
//! Currently, observer entities are never cleaned up, even if their target entity(s) are despawned.
113+
//! This won't cause any runtime overhead, but is a waste of memory and can result in memory leaks.
114+
//!
115+
//! If you run into this problem, you could manually scan the world for observer entities and despawn them,
116+
//! by checking if the entity in [`Observer::descriptor`] still exists.
117+
//!
118+
//! ## Observers vs buffered events
119+
//!
120+
//! By contrast, [`EventReader`] and [`EventWriter`] ("buffered events"), are pull-based.
121+
//! They require periodically polling the world to check for new events, typically in a system that runs as part of a schedule.
122+
//!
123+
//! This imposes a small overhead, making observers a better choice for extremely rare events,
124+
//! but buffered events can be more efficient for events that are expected to occur multiple times per frame,
125+
//! as it allows for batch processing of events.
126+
//!
127+
//! The difference in timing is also an important consideration:
128+
//! buffered events are evaluated at fixed points during schedules,
129+
//! while observers are evaluated as soon as possible after the event is triggered.
130+
//!
131+
//! This provides more control over the timing of buffered event evaluation,
132+
//! but allows for a more ad hoc approach with observers,
133+
//! and enables indefinite chaining of observers triggering other observers (for both better and worse!).
2134
3135
mod entity_observer;
4136
mod runner;
@@ -29,6 +161,17 @@ use smallvec::SmallVec;
29161
/// Type containing triggered [`Event`] information for a given run of an [`Observer`]. This contains the
30162
/// [`Event`] data itself. If it was triggered for a specific [`Entity`], it includes that as well. It also
31163
/// contains event propagation information. See [`Trigger::propagate`] for more information.
164+
///
165+
/// The generic `B: Bundle` is used to modify the further specialize the events that this observer is interested in.
166+
/// The entity involved *does not* have to have these components, but the observer will only be
167+
/// triggered if the event matches the components in `B`.
168+
///
169+
/// This is used to to avoid providing a generic argument in your event, as is done for [`OnAdd`]
170+
/// and the other lifecycle events.
171+
///
172+
/// Providing multiple components in this bundle will cause this event to be triggered by any
173+
/// matching component in the bundle,
174+
/// [rather than requiring all of them to be present](https://github.com/bevyengine/bevy/issues/15325).
32175
pub struct Trigger<'w, E, B: Bundle = ()> {
33176
event: &'w mut E,
34177
propagate: &'w mut bool,
@@ -69,18 +212,6 @@ impl<'w, E, B: Bundle> Trigger<'w, E, B> {
69212

70213
/// Returns the [`Entity`] that was targeted by the `event` that triggered this observer. It may
71214
/// be [`None`] if the trigger is not for a particular entity.
72-
///
73-
/// Observable events can target specific entities. When those events fire, they will trigger
74-
/// any observers on the targeted entities. In this case, the `target()` and `observer()` are
75-
/// the same, because the observer that was triggered is attached to the entity that was
76-
/// targeted by the event.
77-
///
78-
/// However, it is also possible for those events to bubble up the entity hierarchy and trigger
79-
/// observers on *different* entities, or trigger a global observer. In these cases, the
80-
/// observing entity is *different* from the entity being targeted by the event.
81-
///
82-
/// This is an important distinction: the entity reacting to an event is not always the same as
83-
/// the entity triggered by the event.
84215
pub fn target(&self) -> Option<Entity> {
85216
self.trigger.target
86217
}
@@ -172,10 +303,14 @@ impl<'w, E, B: Bundle> DerefMut for Trigger<'w, E, B> {
172303
}
173304
}
174305

175-
/// Represents a collection of targets for a specific [`Trigger`] of an [`Event`]. Targets can be of type [`Entity`] or [`ComponentId`].
306+
/// Represents a collection of targets for a specific [`Trigger`] of an [`Event`].
176307
///
177308
/// When a trigger occurs for a given event and [`TriggerTargets`], any [`Observer`] that watches for that specific event-target combination
178309
/// will run.
310+
///
311+
/// This trait is implemented for both [`Entity`] and [`ComponentId`], allowing you to target specific entities or components.
312+
/// It is also implemented for various collections of these types, such as [`Vec`], arrays, and tuples,
313+
/// allowing you to trigger events for multiple targets at once.
179314
pub trait TriggerTargets {
180315
/// The components the trigger should target.
181316
fn components(&self) -> impl Iterator<Item = ComponentId> + Clone + '_;
@@ -280,7 +415,9 @@ all_tuples!(
280415
T
281416
);
282417

283-
/// A description of what an [`Observer`] observes.
418+
/// Store information about what an [`Observer`] observes.
419+
///
420+
/// This information is stored inside of the [`Observer`] component,
284421
#[derive(Default, Clone)]
285422
pub struct ObserverDescriptor {
286423
/// The events the observer is watching.
@@ -331,7 +468,9 @@ impl ObserverDescriptor {
331468
}
332469
}
333470

334-
/// Event trigger metadata for a given [`Observer`],
471+
/// Metadata about a specific [`Event`] which triggered an observer.
472+
///
473+
/// This information is exposed via methods on the [`Trigger`] system parameter.
335474
#[derive(Debug)]
336475
pub struct ObserverTrigger {
337476
/// The [`Entity`] of the observer handling the trigger.
@@ -357,6 +496,8 @@ impl ObserverTrigger {
357496
type ObserverMap = EntityHashMap<ObserverRunner>;
358497

359498
/// Collection of [`ObserverRunner`] for [`Observer`] registered to a particular trigger targeted at a specific component.
499+
///
500+
/// This is stored inside of [`CachedObservers`].
360501
#[derive(Default, Debug)]
361502
pub struct CachedComponentObservers {
362503
// Observers listening to triggers targeting this component
@@ -366,6 +507,8 @@ pub struct CachedComponentObservers {
366507
}
367508

368509
/// Collection of [`ObserverRunner`] for [`Observer`] registered to a particular trigger.
510+
///
511+
/// This is stored inside of [`Observers`], specialized for each kind of observer.
369512
#[derive(Default, Debug)]
370513
pub struct CachedObservers {
371514
// Observers listening for any time this trigger is fired
@@ -376,7 +519,13 @@ pub struct CachedObservers {
376519
entity_observers: EntityHashMap<ObserverMap>,
377520
}
378521

379-
/// Metadata for observers. Stores a cache mapping trigger ids to the registered observers.
522+
/// An internal lookup table tracking all of the observers in the world.
523+
///
524+
/// Stores a cache mapping trigger ids to the registered observers.
525+
/// Some observer kinds (like [lifecycle](crate::lifecycle) observers) have a dedicated field,
526+
/// saving lookups for the most common triggers.
527+
///
528+
/// This is stored as a field of the [`World`].
380529
#[derive(Default, Debug)]
381530
pub struct Observers {
382531
// Cached ECS observers to save a lookup most common triggers.
@@ -385,7 +534,7 @@ pub struct Observers {
385534
on_replace: CachedObservers,
386535
on_remove: CachedObservers,
387536
on_despawn: CachedObservers,
388-
// Map from trigger type to set of observers
537+
// Map from trigger type to set of observers listening to that trigger
389538
cache: HashMap<ComponentId, CachedObservers>,
390539
}
391540

examples/asset/asset_settings.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
4040
// filtering. This tends to work much better for pixel art assets.
4141
// A good reference when filling this out is to check out [ImageLoaderSettings::default()]
4242
// and follow to the default implementation of each fields type.
43-
// https://docs.rs/bevy/latest/bevy/render/texture/struct.ImageLoaderSettings.html#
43+
// https://docs.rs/bevy/latest/bevy/image/struct.ImageLoaderSettings.html
4444
commands.spawn((
4545
Sprite {
4646
image: asset_server.load("bevy_pixel_dark_with_meta.png"),

0 commit comments

Comments
 (0)