Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/lifecycle.rs
6849 views
1
//! This module contains various tools to allow you to react to component insertion or removal,
2
//! as well as entity spawning and despawning.
3
//!
4
//! There are four main ways to react to these lifecycle events:
5
//!
6
//! 1. Using component hooks, which act as inherent constructors and destructors for components.
7
//! 2. Using [observers], which are a user-extensible way to respond to events, including component lifecycle events.
8
//! 3. Using the [`RemovedComponents`] system parameter, which offers an event-style interface.
9
//! 4. Using the [`Added`] query filter, which checks each component to see if it has been added since the last time a system ran.
10
//!
11
//! [observers]: crate::observer
12
//! [`Added`]: crate::query::Added
13
//!
14
//! # Types of lifecycle events
15
//!
16
//! There are five types of lifecycle events, split into two categories. First, we have lifecycle events that are triggered
17
//! when a component is added to an entity:
18
//!
19
//! - [`Add`]: Triggered when a component is added to an entity that did not already have it.
20
//! - [`Insert`]: Triggered when a component is added to an entity, regardless of whether it already had it.
21
//!
22
//! When both events occur, [`Add`] hooks are evaluated before [`Insert`].
23
//!
24
//! Next, we have lifecycle events that are triggered when a component is removed from an entity:
25
//!
26
//! - [`Replace`]: Triggered when a component is removed from an entity, regardless if it is then replaced with a new value.
27
//! - [`Remove`]: Triggered when a component is removed from an entity and not replaced, before the component is removed.
28
//! - [`Despawn`]: Triggered for each component on an entity when it is despawned.
29
//!
30
//! [`Replace`] hooks are evaluated before [`Remove`], then finally [`Despawn`] hooks are evaluated.
31
//!
32
//! [`Add`] and [`Remove`] are counterparts: they are only triggered when a component is added or removed
33
//! from an entity in such a way as to cause a change in the component's presence on that entity.
34
//! Similarly, [`Insert`] and [`Replace`] are counterparts: they are triggered when a component is added or replaced
35
//! on an entity, regardless of whether this results in a change in the component's presence on that entity.
36
//!
37
//! To reliably synchronize data structures using with component lifecycle events,
38
//! you can combine [`Insert`] and [`Replace`] to fully capture any changes to the data.
39
//! This is particularly useful in combination with immutable components,
40
//! to avoid any lifecycle-bypassing mutations.
41
//!
42
//! ## Lifecycle events and component types
43
//!
44
//! Despite the absence of generics, each lifecycle event is associated with a specific component.
45
//! When defining a component hook for a [`Component`] type, that component is used.
46
//! When observers watch lifecycle events, the `B: Bundle` generic is used.
47
//!
48
//! Each of these lifecycle events also corresponds to a fixed [`ComponentId`],
49
//! which are assigned during [`World`] initialization.
50
//! For example, [`Add`] corresponds to [`ADD`].
51
//! This is used to skip [`TypeId`](core::any::TypeId) lookups in hot paths.
52
use crate::{
53
change_detection::MaybeLocation,
54
component::{Component, ComponentId, ComponentIdFor, Tick},
55
entity::Entity,
56
event::{EntityComponentsTrigger, EntityEvent, EventKey},
57
message::{
58
Message, MessageCursor, MessageId, MessageIterator, MessageIteratorWithId, Messages,
59
},
60
query::FilteredAccessSet,
61
relationship::RelationshipHookMode,
62
storage::SparseSet,
63
system::{Local, ReadOnlySystemParam, SystemMeta, SystemParam},
64
world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, World},
65
};
66
67
use derive_more::derive::Into;
68
69
#[cfg(feature = "bevy_reflect")]
70
use bevy_reflect::Reflect;
71
use core::{
72
fmt::Debug,
73
iter,
74
marker::PhantomData,
75
ops::{Deref, DerefMut},
76
option,
77
};
78
79
/// The type used for [`Component`] lifecycle hooks such as `on_add`, `on_insert` or `on_remove`.
80
pub type ComponentHook = for<'w> fn(DeferredWorld<'w>, HookContext);
81
82
/// Context provided to a [`ComponentHook`].
83
#[derive(Clone, Copy, Debug)]
84
pub struct HookContext {
85
/// The [`Entity`] this hook was invoked for.
86
pub entity: Entity,
87
/// The [`ComponentId`] this hook was invoked for.
88
pub component_id: ComponentId,
89
/// The caller location is `Some` if the `track_caller` feature is enabled.
90
pub caller: MaybeLocation,
91
/// Configures how relationship hooks will run
92
pub relationship_hook_mode: RelationshipHookMode,
93
}
94
95
/// [`World`]-mutating functions that run as part of lifecycle events of a [`Component`].
96
///
97
/// Hooks are functions that run when a component is added, overwritten, or removed from an entity.
98
/// These are intended to be used for structural side effects that need to happen when a component is added or removed,
99
/// and are not intended for general-purpose logic.
100
///
101
/// For example, you might use a hook to update a cached index when a component is added,
102
/// to clean up resources when a component is removed,
103
/// or to keep hierarchical data structures across entities in sync.
104
///
105
/// This information is stored in the [`ComponentInfo`](crate::component::ComponentInfo) of the associated component.
106
///
107
/// There are two ways of configuring hooks for a component:
108
/// 1. Defining the relevant hooks on the [`Component`] implementation
109
/// 2. Using the [`World::register_component_hooks`] method
110
///
111
/// # Example
112
///
113
/// ```
114
/// use bevy_ecs::prelude::*;
115
/// use bevy_platform::collections::HashSet;
116
///
117
/// #[derive(Component)]
118
/// struct MyTrackedComponent;
119
///
120
/// #[derive(Resource, Default)]
121
/// struct TrackedEntities(HashSet<Entity>);
122
///
123
/// let mut world = World::new();
124
/// world.init_resource::<TrackedEntities>();
125
///
126
/// // No entities with `MyTrackedComponent` have been added yet, so we can safely add component hooks
127
/// let mut tracked_component_query = world.query::<&MyTrackedComponent>();
128
/// assert!(tracked_component_query.iter(&world).next().is_none());
129
///
130
/// world.register_component_hooks::<MyTrackedComponent>().on_add(|mut world, context| {
131
/// let mut tracked_entities = world.resource_mut::<TrackedEntities>();
132
/// tracked_entities.0.insert(context.entity);
133
/// });
134
///
135
/// world.register_component_hooks::<MyTrackedComponent>().on_remove(|mut world, context| {
136
/// let mut tracked_entities = world.resource_mut::<TrackedEntities>();
137
/// tracked_entities.0.remove(&context.entity);
138
/// });
139
///
140
/// let entity = world.spawn(MyTrackedComponent).id();
141
/// let tracked_entities = world.resource::<TrackedEntities>();
142
/// assert!(tracked_entities.0.contains(&entity));
143
///
144
/// world.despawn(entity);
145
/// let tracked_entities = world.resource::<TrackedEntities>();
146
/// assert!(!tracked_entities.0.contains(&entity));
147
/// ```
148
#[derive(Debug, Clone, Default)]
149
pub struct ComponentHooks {
150
pub(crate) on_add: Option<ComponentHook>,
151
pub(crate) on_insert: Option<ComponentHook>,
152
pub(crate) on_replace: Option<ComponentHook>,
153
pub(crate) on_remove: Option<ComponentHook>,
154
pub(crate) on_despawn: Option<ComponentHook>,
155
}
156
157
impl ComponentHooks {
158
pub(crate) fn update_from_component<C: Component + ?Sized>(&mut self) -> &mut Self {
159
if let Some(hook) = C::on_add() {
160
self.on_add(hook);
161
}
162
if let Some(hook) = C::on_insert() {
163
self.on_insert(hook);
164
}
165
if let Some(hook) = C::on_replace() {
166
self.on_replace(hook);
167
}
168
if let Some(hook) = C::on_remove() {
169
self.on_remove(hook);
170
}
171
if let Some(hook) = C::on_despawn() {
172
self.on_despawn(hook);
173
}
174
175
self
176
}
177
178
/// Register a [`ComponentHook`] that will be run when this component is added to an entity.
179
/// An `on_add` hook will always run before `on_insert` hooks. Spawning an entity counts as
180
/// adding all of its components.
181
///
182
/// # Panics
183
///
184
/// Will panic if the component already has an `on_add` hook
185
pub fn on_add(&mut self, hook: ComponentHook) -> &mut Self {
186
self.try_on_add(hook)
187
.expect("Component already has an on_add hook")
188
}
189
190
/// Register a [`ComponentHook`] that will be run when this component is added (with `.insert`)
191
/// or replaced.
192
///
193
/// An `on_insert` hook always runs after any `on_add` hooks (if the entity didn't already have the component).
194
///
195
/// # Warning
196
///
197
/// The hook won't run if the component is already present and is only mutated, such as in a system via a query.
198
/// As a result, this needs to be combined with immutable components to serve as a mechanism for reliably updating indexes and other caches.
199
///
200
/// # Panics
201
///
202
/// Will panic if the component already has an `on_insert` hook
203
pub fn on_insert(&mut self, hook: ComponentHook) -> &mut Self {
204
self.try_on_insert(hook)
205
.expect("Component already has an on_insert hook")
206
}
207
208
/// Register a [`ComponentHook`] that will be run when this component is about to be dropped,
209
/// such as being replaced (with `.insert`) or removed.
210
///
211
/// If this component is inserted onto an entity that already has it, this hook will run before the value is replaced,
212
/// allowing access to the previous data just before it is dropped.
213
/// This hook does *not* run if the entity did not already have this component.
214
///
215
/// An `on_replace` hook always runs before any `on_remove` hooks (if the component is being removed from the entity).
216
///
217
/// # Warning
218
///
219
/// The hook won't run if the component is already present and is only mutated, such as in a system via a query.
220
/// As a result, this needs to be combined with immutable components to serve as a mechanism for reliably updating indexes and other caches.
221
///
222
/// # Panics
223
///
224
/// Will panic if the component already has an `on_replace` hook
225
pub fn on_replace(&mut self, hook: ComponentHook) -> &mut Self {
226
self.try_on_replace(hook)
227
.expect("Component already has an on_replace hook")
228
}
229
230
/// Register a [`ComponentHook`] that will be run when this component is removed from an entity.
231
/// Despawning an entity counts as removing all of its components.
232
///
233
/// # Panics
234
///
235
/// Will panic if the component already has an `on_remove` hook
236
pub fn on_remove(&mut self, hook: ComponentHook) -> &mut Self {
237
self.try_on_remove(hook)
238
.expect("Component already has an on_remove hook")
239
}
240
241
/// Register a [`ComponentHook`] that will be run for each component on an entity when it is despawned.
242
///
243
/// # Panics
244
///
245
/// Will panic if the component already has an `on_despawn` hook
246
pub fn on_despawn(&mut self, hook: ComponentHook) -> &mut Self {
247
self.try_on_despawn(hook)
248
.expect("Component already has an on_despawn hook")
249
}
250
251
/// Attempt to register a [`ComponentHook`] that will be run when this component is added to an entity.
252
///
253
/// This is a fallible version of [`Self::on_add`].
254
///
255
/// Returns `None` if the component already has an `on_add` hook.
256
pub fn try_on_add(&mut self, hook: ComponentHook) -> Option<&mut Self> {
257
if self.on_add.is_some() {
258
return None;
259
}
260
self.on_add = Some(hook);
261
Some(self)
262
}
263
264
/// Attempt to register a [`ComponentHook`] that will be run when this component is added (with `.insert`)
265
///
266
/// This is a fallible version of [`Self::on_insert`].
267
///
268
/// Returns `None` if the component already has an `on_insert` hook.
269
pub fn try_on_insert(&mut self, hook: ComponentHook) -> Option<&mut Self> {
270
if self.on_insert.is_some() {
271
return None;
272
}
273
self.on_insert = Some(hook);
274
Some(self)
275
}
276
277
/// Attempt to register a [`ComponentHook`] that will be run when this component is replaced (with `.insert`) or removed
278
///
279
/// This is a fallible version of [`Self::on_replace`].
280
///
281
/// Returns `None` if the component already has an `on_replace` hook.
282
pub fn try_on_replace(&mut self, hook: ComponentHook) -> Option<&mut Self> {
283
if self.on_replace.is_some() {
284
return None;
285
}
286
self.on_replace = Some(hook);
287
Some(self)
288
}
289
290
/// Attempt to register a [`ComponentHook`] that will be run when this component is removed from an entity.
291
///
292
/// This is a fallible version of [`Self::on_remove`].
293
///
294
/// Returns `None` if the component already has an `on_remove` hook.
295
pub fn try_on_remove(&mut self, hook: ComponentHook) -> Option<&mut Self> {
296
if self.on_remove.is_some() {
297
return None;
298
}
299
self.on_remove = Some(hook);
300
Some(self)
301
}
302
303
/// Attempt to register a [`ComponentHook`] that will be run for each component on an entity when it is despawned.
304
///
305
/// This is a fallible version of [`Self::on_despawn`].
306
///
307
/// Returns `None` if the component already has an `on_despawn` hook.
308
pub fn try_on_despawn(&mut self, hook: ComponentHook) -> Option<&mut Self> {
309
if self.on_despawn.is_some() {
310
return None;
311
}
312
self.on_despawn = Some(hook);
313
Some(self)
314
}
315
}
316
317
/// [`EventKey`] for [`Add`]
318
pub const ADD: EventKey = EventKey(ComponentId::new(0));
319
/// [`EventKey`] for [`Insert`]
320
pub const INSERT: EventKey = EventKey(ComponentId::new(1));
321
/// [`EventKey`] for [`Replace`]
322
pub const REPLACE: EventKey = EventKey(ComponentId::new(2));
323
/// [`EventKey`] for [`Remove`]
324
pub const REMOVE: EventKey = EventKey(ComponentId::new(3));
325
/// [`EventKey`] for [`Despawn`]
326
pub const DESPAWN: EventKey = EventKey(ComponentId::new(4));
327
328
/// Trigger emitted when a component is inserted onto an entity that does not already have that
329
/// component. Runs before `Insert`.
330
/// See [`ComponentHooks::on_add`](`crate::lifecycle::ComponentHooks::on_add`) for more information.
331
#[derive(Debug, Clone, EntityEvent)]
332
#[entity_event(trigger = EntityComponentsTrigger<'a>)]
333
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
334
#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]
335
#[doc(alias = "OnAdd")]
336
pub struct Add {
337
/// The entity this component was added to.
338
pub entity: Entity,
339
}
340
341
/// Trigger emitted when a component is inserted, regardless of whether or not the entity already
342
/// had that component. Runs after `Add`, if it ran.
343
/// See [`ComponentHooks::on_insert`](`crate::lifecycle::ComponentHooks::on_insert`) for more information.
344
#[derive(Debug, Clone, EntityEvent)]
345
#[entity_event(trigger = EntityComponentsTrigger<'a>)]
346
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
347
#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]
348
#[doc(alias = "OnInsert")]
349
pub struct Insert {
350
/// The entity this component was inserted into.
351
pub entity: Entity,
352
}
353
354
/// Trigger emitted when a component is removed from an entity, regardless
355
/// of whether or not it is later replaced.
356
///
357
/// Runs before the value is replaced, so you can still access the original component data.
358
/// See [`ComponentHooks::on_replace`](`crate::lifecycle::ComponentHooks::on_replace`) for more information.
359
#[derive(Debug, Clone, EntityEvent)]
360
#[entity_event(trigger = EntityComponentsTrigger<'a>)]
361
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
362
#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]
363
#[doc(alias = "OnReplace")]
364
pub struct Replace {
365
/// The entity that held this component before it was replaced.
366
pub entity: Entity,
367
}
368
369
/// Trigger emitted when a component is removed from an entity, and runs before the component is
370
/// removed, so you can still access the component data.
371
/// See [`ComponentHooks::on_remove`](`crate::lifecycle::ComponentHooks::on_remove`) for more information.
372
#[derive(Debug, Clone, EntityEvent)]
373
#[entity_event(trigger = EntityComponentsTrigger<'a>)]
374
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
375
#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]
376
#[doc(alias = "OnRemove")]
377
pub struct Remove {
378
/// The entity this component was removed from.
379
pub entity: Entity,
380
}
381
382
/// [`EntityEvent`] emitted for each component on an entity when it is despawned.
383
/// See [`ComponentHooks::on_despawn`](`crate::lifecycle::ComponentHooks::on_despawn`) for more information.
384
#[derive(Debug, Clone, EntityEvent)]
385
#[entity_event(trigger = EntityComponentsTrigger<'a>)]
386
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
387
#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]
388
#[doc(alias = "OnDespawn")]
389
pub struct Despawn {
390
/// The entity that held this component before it was despawned.
391
pub entity: Entity,
392
}
393
394
/// Deprecated in favor of [`Add`].
395
#[deprecated(since = "0.17.0", note = "Renamed to `Add`.")]
396
pub type OnAdd = Add;
397
398
/// Deprecated in favor of [`Insert`].
399
#[deprecated(since = "0.17.0", note = "Renamed to `Insert`.")]
400
pub type OnInsert = Insert;
401
402
/// Deprecated in favor of [`Replace`].
403
#[deprecated(since = "0.17.0", note = "Renamed to `Replace`.")]
404
pub type OnReplace = Replace;
405
406
/// Deprecated in favor of [`Remove`].
407
#[deprecated(since = "0.17.0", note = "Renamed to `Remove`.")]
408
pub type OnRemove = Remove;
409
410
/// Deprecated in favor of [`Despawn`].
411
#[deprecated(since = "0.17.0", note = "Renamed to `Despawn`.")]
412
pub type OnDespawn = Despawn;
413
414
/// Wrapper around [`Entity`] for [`RemovedComponents`].
415
/// Internally, `RemovedComponents` uses these as an [`Messages<RemovedComponentEntity>`].
416
#[derive(Message, Debug, Clone, Into)]
417
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
418
#[cfg_attr(feature = "bevy_reflect", reflect(Debug, Clone))]
419
pub struct RemovedComponentEntity(Entity);
420
421
/// Wrapper around a [`MessageCursor<RemovedComponentEntity>`] so that we
422
/// can differentiate messages between components.
423
#[derive(Debug)]
424
pub struct RemovedComponentReader<T>
425
where
426
T: Component,
427
{
428
reader: MessageCursor<RemovedComponentEntity>,
429
marker: PhantomData<T>,
430
}
431
432
impl<T: Component> Default for RemovedComponentReader<T> {
433
fn default() -> Self {
434
Self {
435
reader: Default::default(),
436
marker: PhantomData,
437
}
438
}
439
}
440
441
impl<T: Component> Deref for RemovedComponentReader<T> {
442
type Target = MessageCursor<RemovedComponentEntity>;
443
fn deref(&self) -> &Self::Target {
444
&self.reader
445
}
446
}
447
448
impl<T: Component> DerefMut for RemovedComponentReader<T> {
449
fn deref_mut(&mut self) -> &mut Self::Target {
450
&mut self.reader
451
}
452
}
453
/// Renamed to [`RemovedComponentMessages`].
454
#[deprecated(since = "0.17.0", note = "Use `RemovedComponentMessages` instead.")]
455
pub type RemovedComponentEvents = RemovedComponentMessages;
456
457
/// Stores the [`RemovedComponents`] event buffers for all types of component in a given [`World`].
458
#[derive(Default, Debug)]
459
pub struct RemovedComponentMessages {
460
event_sets: SparseSet<ComponentId, Messages<RemovedComponentEntity>>,
461
}
462
463
impl RemovedComponentMessages {
464
/// Creates an empty storage buffer for component removal messages.
465
pub fn new() -> Self {
466
Self::default()
467
}
468
469
/// For each type of component, swaps the event buffers and clears the oldest event buffer.
470
/// In general, this should be called once per frame/update.
471
pub fn update(&mut self) {
472
for (_component_id, messages) in self.event_sets.iter_mut() {
473
messages.update();
474
}
475
}
476
477
/// Returns an iterator over components and their entity messages.
478
pub fn iter(&self) -> impl Iterator<Item = (&ComponentId, &Messages<RemovedComponentEntity>)> {
479
self.event_sets.iter()
480
}
481
482
/// Gets the event storage for a given component.
483
pub fn get(
484
&self,
485
component_id: impl Into<ComponentId>,
486
) -> Option<&Messages<RemovedComponentEntity>> {
487
self.event_sets.get(component_id.into())
488
}
489
490
/// Sends a removal message for the specified component.
491
#[deprecated(
492
since = "0.17.0",
493
note = "Use `RemovedComponentMessages:write` instead."
494
)]
495
pub fn send(&mut self, component_id: impl Into<ComponentId>, entity: Entity) {
496
self.write(component_id, entity);
497
}
498
499
/// Writes a removal message for the specified component.
500
pub fn write(&mut self, component_id: impl Into<ComponentId>, entity: Entity) {
501
self.event_sets
502
.get_or_insert_with(component_id.into(), Default::default)
503
.write(RemovedComponentEntity(entity));
504
}
505
}
506
507
/// A [`SystemParam`] that yields entities that had their `T` [`Component`]
508
/// removed or have been despawned with it.
509
///
510
/// This acts effectively the same as a [`MessageReader`](crate::message::MessageReader).
511
///
512
/// Unlike hooks or observers (see the [lifecycle](crate) module docs),
513
/// this does not allow you to see which data existed before removal.
514
///
515
/// If you are using `bevy_ecs` as a standalone crate,
516
/// note that the [`RemovedComponents`] list will not be automatically cleared for you,
517
/// and will need to be manually flushed using [`World::clear_trackers`](World::clear_trackers).
518
///
519
/// For users of `bevy` and `bevy_app`, [`World::clear_trackers`](World::clear_trackers) is
520
/// automatically called by `bevy_app::App::update` and `bevy_app::SubApp::update`.
521
/// For the main world, this is delayed until after all `SubApp`s have run.
522
///
523
/// # Examples
524
///
525
/// Basic usage:
526
///
527
/// ```
528
/// # use bevy_ecs::component::Component;
529
/// # use bevy_ecs::system::IntoSystem;
530
/// # use bevy_ecs::lifecycle::RemovedComponents;
531
/// #
532
/// # #[derive(Component)]
533
/// # struct MyComponent;
534
/// fn react_on_removal(mut removed: RemovedComponents<MyComponent>) {
535
/// removed.read().for_each(|removed_entity| println!("{}", removed_entity));
536
/// }
537
/// # bevy_ecs::system::assert_is_system(react_on_removal);
538
/// ```
539
#[derive(SystemParam)]
540
pub struct RemovedComponents<'w, 's, T: Component> {
541
component_id: ComponentIdFor<'s, T>,
542
reader: Local<'s, RemovedComponentReader<T>>,
543
message_sets: &'w RemovedComponentMessages,
544
}
545
546
/// Iterator over entities that had a specific component removed.
547
///
548
/// See [`RemovedComponents`].
549
pub type RemovedIter<'a> = iter::Map<
550
iter::Flatten<option::IntoIter<iter::Cloned<MessageIterator<'a, RemovedComponentEntity>>>>,
551
fn(RemovedComponentEntity) -> Entity,
552
>;
553
554
/// Iterator over entities that had a specific component removed.
555
///
556
/// See [`RemovedComponents`].
557
pub type RemovedIterWithId<'a> = iter::Map<
558
iter::Flatten<option::IntoIter<MessageIteratorWithId<'a, RemovedComponentEntity>>>,
559
fn(
560
(&RemovedComponentEntity, MessageId<RemovedComponentEntity>),
561
) -> (Entity, MessageId<RemovedComponentEntity>),
562
>;
563
564
fn map_id_messages(
565
(entity, id): (&RemovedComponentEntity, MessageId<RemovedComponentEntity>),
566
) -> (Entity, MessageId<RemovedComponentEntity>) {
567
(entity.clone().into(), id)
568
}
569
570
// For all practical purposes, the api surface of `RemovedComponents<T>`
571
// should be similar to `MessageReader<T>` to reduce confusion.
572
impl<'w, 's, T: Component> RemovedComponents<'w, 's, T> {
573
/// Fetch underlying [`MessageCursor`].
574
pub fn reader(&self) -> &MessageCursor<RemovedComponentEntity> {
575
&self.reader
576
}
577
578
/// Fetch underlying [`MessageCursor`] mutably.
579
pub fn reader_mut(&mut self) -> &mut MessageCursor<RemovedComponentEntity> {
580
&mut self.reader
581
}
582
583
/// Fetch underlying [`Messages`].
584
#[deprecated(since = "0.17.0", note = "Renamed to `messages`.")]
585
pub fn events(&self) -> Option<&Messages<RemovedComponentEntity>> {
586
self.messages()
587
}
588
589
/// Fetch underlying [`Messages`].
590
pub fn messages(&self) -> Option<&Messages<RemovedComponentEntity>> {
591
self.message_sets.get(self.component_id.get())
592
}
593
594
/// Destructures to get a mutable reference to the `MessageCursor`
595
/// and a reference to `Messages`.
596
///
597
/// This is necessary since Rust can't detect destructuring through methods and most
598
/// usecases of the reader uses the `Messages` as well.
599
pub fn reader_mut_with_messages(
600
&mut self,
601
) -> Option<(
602
&mut RemovedComponentReader<T>,
603
&Messages<RemovedComponentEntity>,
604
)> {
605
self.message_sets
606
.get(self.component_id.get())
607
.map(|messages| (&mut *self.reader, messages))
608
}
609
610
/// Destructures to get a reference to the `MessageCursor`
611
/// and a reference to `Messages`.
612
#[deprecated(since = "0.17.0", note = "Renamed to `reader_mut_with_messages`.")]
613
pub fn reader_mut_with_events(
614
&mut self,
615
) -> Option<(
616
&mut RemovedComponentReader<T>,
617
&Messages<RemovedComponentEntity>,
618
)> {
619
self.reader_mut_with_messages()
620
}
621
622
/// Iterates over the messages this [`RemovedComponents`] has not seen yet. This updates the
623
/// [`RemovedComponents`]'s message counter, which means subsequent message reads will not include messages
624
/// that happened before now.
625
pub fn read(&mut self) -> RemovedIter<'_> {
626
self.reader_mut_with_messages()
627
.map(|(reader, messages)| reader.read(messages).cloned())
628
.into_iter()
629
.flatten()
630
.map(RemovedComponentEntity::into)
631
}
632
633
/// Like [`read`](Self::read), except also returning the [`MessageId`] of the messages.
634
pub fn read_with_id(&mut self) -> RemovedIterWithId<'_> {
635
self.reader_mut_with_messages()
636
.map(|(reader, messages)| reader.read_with_id(messages))
637
.into_iter()
638
.flatten()
639
.map(map_id_messages)
640
}
641
642
/// Determines the number of removal messages available to be read from this [`RemovedComponents`] without consuming any.
643
pub fn len(&self) -> usize {
644
self.messages()
645
.map(|messages| self.reader.len(messages))
646
.unwrap_or(0)
647
}
648
649
/// Returns `true` if there are no messages available to read.
650
pub fn is_empty(&self) -> bool {
651
self.messages()
652
.is_none_or(|messages| self.reader.is_empty(messages))
653
}
654
655
/// Consumes all available messages.
656
///
657
/// This means these messages will not appear in calls to [`RemovedComponents::read()`] or
658
/// [`RemovedComponents::read_with_id()`] and [`RemovedComponents::is_empty()`] will return `true`.
659
pub fn clear(&mut self) {
660
if let Some((reader, messages)) = self.reader_mut_with_messages() {
661
reader.clear(messages);
662
}
663
}
664
}
665
666
// SAFETY: Only reads World removed component messages
667
unsafe impl<'a> ReadOnlySystemParam for &'a RemovedComponentMessages {}
668
669
// SAFETY: no component value access.
670
unsafe impl<'a> SystemParam for &'a RemovedComponentMessages {
671
type State = ();
672
type Item<'w, 's> = &'w RemovedComponentMessages;
673
674
fn init_state(_world: &mut World) -> Self::State {}
675
676
fn init_access(
677
_state: &Self::State,
678
_system_meta: &mut SystemMeta,
679
_component_access_set: &mut FilteredAccessSet,
680
_world: &mut World,
681
) {
682
}
683
684
#[inline]
685
unsafe fn get_param<'w, 's>(
686
_state: &'s mut Self::State,
687
_system_meta: &SystemMeta,
688
world: UnsafeWorldCell<'w>,
689
_change_tick: Tick,
690
) -> Self::Item<'w, 's> {
691
world.removed_components()
692
}
693
}
694
695