Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/world/deferred_world.rs
9418 views
1
use core::ops::Deref;
2
3
use bevy_utils::prelude::DebugName;
4
5
use crate::{
6
archetype::Archetype,
7
change_detection::{MaybeLocation, MutUntyped},
8
component::{ComponentId, Mutable},
9
entity::Entity,
10
event::{EntityComponentsTrigger, Event, EventKey, Trigger},
11
lifecycle::{Discard, HookContext, Insert, DISCARD, INSERT},
12
message::{Message, MessageId, Messages, WriteBatchIds},
13
observer::TriggerContext,
14
prelude::{Component, QueryState},
15
query::{QueryData, QueryFilter},
16
relationship::RelationshipHookMode,
17
resource::Resource,
18
system::{Commands, Query},
19
world::{error::EntityMutableFetchError, EntityFetcher, WorldEntityFetch},
20
};
21
22
use super::{unsafe_world_cell::UnsafeWorldCell, Mut, World};
23
24
/// A [`World`] reference that disallows structural ECS changes.
25
/// This includes initializing resources, registering components or spawning entities.
26
///
27
/// This means that in order to add entities, for example, you will need to use commands instead of the world directly.
28
pub struct DeferredWorld<'w> {
29
// SAFETY: Implementers must not use this reference to make structural changes
30
world: UnsafeWorldCell<'w>,
31
}
32
33
impl<'w> Deref for DeferredWorld<'w> {
34
type Target = World;
35
36
fn deref(&self) -> &Self::Target {
37
// SAFETY: Structural changes cannot be made through &World
38
unsafe { self.world.world() }
39
}
40
}
41
42
impl<'w> UnsafeWorldCell<'w> {
43
/// Turn self into a [`DeferredWorld`]
44
///
45
/// # Safety
46
/// Caller must ensure there are no outstanding mutable references to world and no
47
/// outstanding references to the world's command queue, resource or component data
48
#[inline]
49
pub unsafe fn into_deferred(self) -> DeferredWorld<'w> {
50
DeferredWorld { world: self }
51
}
52
}
53
54
impl<'w> From<&'w mut World> for DeferredWorld<'w> {
55
fn from(world: &'w mut World) -> DeferredWorld<'w> {
56
DeferredWorld {
57
world: world.as_unsafe_world_cell(),
58
}
59
}
60
}
61
62
impl<'w> DeferredWorld<'w> {
63
/// Reborrow self as a new instance of [`DeferredWorld`]
64
#[inline]
65
pub fn reborrow(&mut self) -> DeferredWorld<'_> {
66
DeferredWorld { world: self.world }
67
}
68
69
/// Creates a [`Commands`] instance that pushes to the world's command queue
70
#[inline]
71
pub fn commands(&mut self) -> Commands<'_, '_> {
72
// SAFETY: &mut self ensure that there are no outstanding accesses to the queue
73
let command_queue = unsafe { self.world.get_raw_command_queue() };
74
// SAFETY: command_queue is stored on world and always valid while the world exists
75
unsafe {
76
Commands::new_raw_from_entities(
77
command_queue,
78
self.world.entity_allocator(),
79
self.world.entities(),
80
)
81
}
82
}
83
84
/// Retrieves a mutable reference to the given `entity`'s [`Component`] of the given type.
85
/// Returns `None` if the `entity` does not have a [`Component`] of the given type.
86
#[inline]
87
pub fn get_mut<T: Component<Mutability = Mutable>>(
88
&mut self,
89
entity: Entity,
90
) -> Option<Mut<'_, T>> {
91
self.get_entity_mut(entity).ok()?.into_mut()
92
}
93
94
/// Temporarily removes a [`Component`] `T` from the provided [`Entity`] and
95
/// runs the provided closure on it, returning the result if `T` was available.
96
/// This will trigger the `Remove` and `Discard` component hooks without
97
/// causing an archetype move.
98
///
99
/// This is most useful with immutable components, where removal and reinsertion
100
/// is the only way to modify a value.
101
///
102
/// If you do not need to ensure the above hooks are triggered, and your component
103
/// is mutable, prefer using [`get_mut`](DeferredWorld::get_mut).
104
#[inline]
105
#[track_caller]
106
pub(crate) fn modify_component_with_relationship_hook_mode<T: Component, R>(
107
&mut self,
108
entity: Entity,
109
relationship_hook_mode: RelationshipHookMode,
110
f: impl FnOnce(&mut T) -> R,
111
) -> Result<Option<R>, EntityMutableFetchError> {
112
// If the component is not registered, then it doesn't exist on this entity, so no action required.
113
let Some(component_id) = self.component_id::<T>() else {
114
return Ok(None);
115
};
116
117
self.modify_component_by_id_with_relationship_hook_mode(
118
entity,
119
component_id,
120
relationship_hook_mode,
121
move |component| {
122
// SAFETY: component matches the component_id collected in the above line
123
let mut component = unsafe { component.with_type::<T>() };
124
125
f(&mut component)
126
},
127
)
128
}
129
130
/// Temporarily removes a [`Component`] identified by the provided
131
/// [`ComponentId`] from the provided [`Entity`] and runs the provided
132
/// closure on it, returning the result if the component was available.
133
/// This will trigger the `Remove` and `Discard` component hooks without
134
/// causing an archetype move.
135
///
136
/// This is most useful with immutable components, where removal and reinsertion
137
/// is the only way to modify a value.
138
///
139
/// If you do not need to ensure the above hooks are triggered, and your component
140
/// is mutable, prefer using [`get_mut_by_id`](DeferredWorld::get_mut_by_id).
141
///
142
/// You should prefer the typed [`modify_component_with_relationship_hook_mode`](DeferredWorld::modify_component_with_relationship_hook_mode)
143
/// whenever possible.
144
#[inline]
145
#[track_caller]
146
pub(crate) fn modify_component_by_id_with_relationship_hook_mode<R>(
147
&mut self,
148
entity: Entity,
149
component_id: ComponentId,
150
relationship_hook_mode: RelationshipHookMode,
151
f: impl for<'a> FnOnce(MutUntyped<'a>) -> R,
152
) -> Result<Option<R>, EntityMutableFetchError> {
153
let entity_cell = self.get_entity_mut(entity)?;
154
155
if !entity_cell.contains_id(component_id) {
156
return Ok(None);
157
}
158
159
let archetype = &raw const *entity_cell.archetype();
160
161
// SAFETY:
162
// - DeferredWorld ensures archetype pointer will remain valid as no
163
// relocations will occur.
164
// - component_id exists on this world and this entity
165
// - DISCARD is able to accept ZST events
166
unsafe {
167
let archetype = &*archetype;
168
self.trigger_on_discard(
169
archetype,
170
entity,
171
[component_id].into_iter(),
172
MaybeLocation::caller(),
173
relationship_hook_mode,
174
);
175
if archetype.has_discard_observer() {
176
// SAFETY: the DISCARD event_key corresponds to the Discard event's type
177
self.trigger_raw(
178
DISCARD,
179
&mut Discard { entity },
180
&mut EntityComponentsTrigger {
181
components: &[component_id],
182
old_archetype: Some(archetype),
183
new_archetype: Some(archetype),
184
},
185
MaybeLocation::caller(),
186
);
187
}
188
}
189
190
let mut entity_cell = self
191
.get_entity_mut(entity)
192
.expect("entity access confirmed above");
193
194
// SAFETY: we will run the required hooks to simulate removal/replacement.
195
let mut component = unsafe {
196
entity_cell
197
.get_mut_assume_mutable_by_id(component_id)
198
.expect("component access confirmed above")
199
};
200
201
let result = f(component.reborrow());
202
203
// Simulate adding this component by updating the relevant ticks
204
*component.ticks.added = *component.ticks.changed;
205
206
// SAFETY:
207
// - DeferredWorld ensures archetype pointer will remain valid as no
208
// relocations will occur.
209
// - component_id exists on this world and this entity
210
// - DISCARD is able to accept ZST events
211
unsafe {
212
let archetype = &*archetype;
213
self.trigger_on_insert(
214
archetype,
215
entity,
216
[component_id].into_iter(),
217
MaybeLocation::caller(),
218
relationship_hook_mode,
219
);
220
if archetype.has_insert_observer() {
221
// SAFETY: the INSERT event_key corresponds to the Insert event's type
222
self.trigger_raw(
223
INSERT,
224
&mut Insert { entity },
225
&mut EntityComponentsTrigger {
226
components: &[component_id],
227
old_archetype: Some(archetype),
228
new_archetype: Some(archetype),
229
},
230
MaybeLocation::caller(),
231
);
232
}
233
}
234
235
Ok(Some(result))
236
}
237
238
/// Returns [`EntityMut`]s that expose read and write operations for the
239
/// given `entities`, returning [`Err`] if any of the given entities do not
240
/// exist. Instead of immediately unwrapping the value returned from this
241
/// function, prefer [`World::entity_mut`].
242
///
243
/// This function supports fetching a single entity or multiple entities:
244
/// - Pass an [`Entity`] to receive a single [`EntityMut`].
245
/// - Pass a slice of [`Entity`]s to receive a [`Vec<EntityMut>`].
246
/// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityMut`]s.
247
/// - Pass an [`&EntityHashSet`] to receive an [`EntityHashMap<EntityMut>`].
248
///
249
/// **As [`DeferredWorld`] does not allow structural changes, all returned
250
/// references are [`EntityMut`]s, which do not allow structural changes
251
/// (i.e. adding/removing components or despawning the entity).**
252
///
253
/// # Errors
254
///
255
/// - Returns [`EntityMutableFetchError::NotSpawned`] if any of the given `entities` do not exist in the world.
256
/// - Only the first entity found to be missing will be returned.
257
/// - Returns [`EntityMutableFetchError::AliasedMutability`] if the same entity is requested multiple times.
258
///
259
/// # Examples
260
///
261
/// For examples, see [`DeferredWorld::entity_mut`].
262
///
263
/// [`EntityMut`]: crate::world::EntityMut
264
/// [`&EntityHashSet`]: crate::entity::EntityHashSet
265
/// [`EntityHashMap<EntityMut>`]: crate::entity::EntityHashMap
266
/// [`Vec<EntityMut>`]: alloc::vec::Vec
267
#[inline]
268
pub fn get_entity_mut<F: WorldEntityFetch>(
269
&mut self,
270
entities: F,
271
) -> Result<F::DeferredMut<'_>, EntityMutableFetchError> {
272
let cell = self.as_unsafe_world_cell();
273
// SAFETY: `&mut self` gives mutable access to the entire world,
274
// and prevents any other access to the world.
275
unsafe { entities.fetch_deferred_mut(cell) }
276
}
277
278
/// Returns [`EntityMut`]s that expose read and write operations for the
279
/// given `entities`. This will panic if any of the given entities do not
280
/// exist. Use [`DeferredWorld::get_entity_mut`] if you want to check for
281
/// entity existence instead of implicitly panicking.
282
///
283
/// This function supports fetching a single entity or multiple entities:
284
/// - Pass an [`Entity`] to receive a single [`EntityMut`].
285
/// - Pass a slice of [`Entity`]s to receive a [`Vec<EntityMut>`].
286
/// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityMut`]s.
287
/// - Pass an [`&EntityHashSet`] to receive an [`EntityHashMap<EntityMut>`].
288
///
289
/// **As [`DeferredWorld`] does not allow structural changes, all returned
290
/// references are [`EntityMut`]s, which do not allow structural changes
291
/// (i.e. adding/removing components or despawning the entity).**
292
///
293
/// # Panics
294
///
295
/// If any of the given `entities` do not exist in the world.
296
///
297
/// # Examples
298
///
299
/// ## Single [`Entity`]
300
///
301
/// ```
302
/// # use bevy_ecs::{prelude::*, world::DeferredWorld};
303
/// #[derive(Component)]
304
/// struct Position {
305
/// x: f32,
306
/// y: f32,
307
/// }
308
///
309
/// # let mut world = World::new();
310
/// # let entity = world.spawn(Position { x: 0.0, y: 0.0 }).id();
311
/// let mut world: DeferredWorld = // ...
312
/// # DeferredWorld::from(&mut world);
313
///
314
/// let mut entity_mut = world.entity_mut(entity);
315
/// let mut position = entity_mut.get_mut::<Position>().unwrap();
316
/// position.y = 1.0;
317
/// assert_eq!(position.x, 0.0);
318
/// ```
319
///
320
/// ## Array of [`Entity`]s
321
///
322
/// ```
323
/// # use bevy_ecs::{prelude::*, world::DeferredWorld};
324
/// #[derive(Component)]
325
/// struct Position {
326
/// x: f32,
327
/// y: f32,
328
/// }
329
///
330
/// # let mut world = World::new();
331
/// # let e1 = world.spawn(Position { x: 0.0, y: 0.0 }).id();
332
/// # let e2 = world.spawn(Position { x: 1.0, y: 1.0 }).id();
333
/// let mut world: DeferredWorld = // ...
334
/// # DeferredWorld::from(&mut world);
335
///
336
/// let [mut e1_ref, mut e2_ref] = world.entity_mut([e1, e2]);
337
/// let mut e1_position = e1_ref.get_mut::<Position>().unwrap();
338
/// e1_position.x = 1.0;
339
/// assert_eq!(e1_position.x, 1.0);
340
/// let mut e2_position = e2_ref.get_mut::<Position>().unwrap();
341
/// e2_position.x = 2.0;
342
/// assert_eq!(e2_position.x, 2.0);
343
/// ```
344
///
345
/// ## Slice of [`Entity`]s
346
///
347
/// ```
348
/// # use bevy_ecs::{prelude::*, world::DeferredWorld};
349
/// #[derive(Component)]
350
/// struct Position {
351
/// x: f32,
352
/// y: f32,
353
/// }
354
///
355
/// # let mut world = World::new();
356
/// # let e1 = world.spawn(Position { x: 0.0, y: 1.0 }).id();
357
/// # let e2 = world.spawn(Position { x: 0.0, y: 1.0 }).id();
358
/// # let e3 = world.spawn(Position { x: 0.0, y: 1.0 }).id();
359
/// let mut world: DeferredWorld = // ...
360
/// # DeferredWorld::from(&mut world);
361
///
362
/// let ids = vec![e1, e2, e3];
363
/// for mut eref in world.entity_mut(&ids[..]) {
364
/// let mut pos = eref.get_mut::<Position>().unwrap();
365
/// pos.y = 2.0;
366
/// assert_eq!(pos.y, 2.0);
367
/// }
368
/// ```
369
///
370
/// ## [`&EntityHashSet`]
371
///
372
/// ```
373
/// # use bevy_ecs::{prelude::*, entity::EntityHashSet, world::DeferredWorld};
374
/// #[derive(Component)]
375
/// struct Position {
376
/// x: f32,
377
/// y: f32,
378
/// }
379
///
380
/// # let mut world = World::new();
381
/// # let e1 = world.spawn(Position { x: 0.0, y: 1.0 }).id();
382
/// # let e2 = world.spawn(Position { x: 0.0, y: 1.0 }).id();
383
/// # let e3 = world.spawn(Position { x: 0.0, y: 1.0 }).id();
384
/// let mut world: DeferredWorld = // ...
385
/// # DeferredWorld::from(&mut world);
386
///
387
/// let ids = EntityHashSet::from_iter([e1, e2, e3]);
388
/// for (_id, mut eref) in world.entity_mut(&ids) {
389
/// let mut pos = eref.get_mut::<Position>().unwrap();
390
/// pos.y = 2.0;
391
/// assert_eq!(pos.y, 2.0);
392
/// }
393
/// ```
394
///
395
/// [`EntityMut`]: crate::world::EntityMut
396
/// [`&EntityHashSet`]: crate::entity::EntityHashSet
397
/// [`EntityHashMap<EntityMut>`]: crate::entity::EntityHashMap
398
/// [`Vec<EntityMut>`]: alloc::vec::Vec
399
#[inline]
400
pub fn entity_mut<F: WorldEntityFetch>(&mut self, entities: F) -> F::DeferredMut<'_> {
401
self.get_entity_mut(entities).unwrap()
402
}
403
404
/// Simultaneously provides access to entity data and a command queue, which
405
/// will be applied when the [`World`] is next flushed.
406
///
407
/// This allows using borrowed entity data to construct commands where the
408
/// borrow checker would otherwise prevent it.
409
///
410
/// See [`World::entities_and_commands`] for the non-deferred version.
411
///
412
/// # Example
413
///
414
/// ```rust
415
/// # use bevy_ecs::{prelude::*, world::DeferredWorld};
416
/// #[derive(Component)]
417
/// struct Targets(Vec<Entity>);
418
/// #[derive(Component)]
419
/// struct TargetedBy(Entity);
420
///
421
/// # let mut _world = World::new();
422
/// # let e1 = _world.spawn_empty().id();
423
/// # let e2 = _world.spawn_empty().id();
424
/// # let eid = _world.spawn(Targets(vec![e1, e2])).id();
425
/// let mut world: DeferredWorld = // ...
426
/// # DeferredWorld::from(&mut _world);
427
/// let (entities, mut commands) = world.entities_and_commands();
428
///
429
/// let entity = entities.get(eid).unwrap();
430
/// for &target in entity.get::<Targets>().unwrap().0.iter() {
431
/// commands.entity(target).insert(TargetedBy(eid));
432
/// }
433
/// # _world.flush();
434
/// # assert_eq!(_world.get::<TargetedBy>(e1).unwrap().0, eid);
435
/// # assert_eq!(_world.get::<TargetedBy>(e2).unwrap().0, eid);
436
/// ```
437
pub fn entities_and_commands(&mut self) -> (EntityFetcher<'_>, Commands<'_, '_>) {
438
let cell = self.as_unsafe_world_cell();
439
// SAFETY: `&mut self` gives mutable access to the entire world, and prevents simultaneous access.
440
let fetcher = unsafe { EntityFetcher::new(cell) };
441
// SAFETY:
442
// - `&mut self` gives mutable access to the entire world, and prevents simultaneous access.
443
// - Command queue access does not conflict with entity access.
444
let raw_queue = unsafe { cell.get_raw_command_queue() };
445
// SAFETY: `&mut self` ensures the commands does not outlive the world.
446
let commands = unsafe {
447
Commands::new_raw_from_entities(raw_queue, cell.entity_allocator(), cell.entities())
448
};
449
450
(fetcher, commands)
451
}
452
453
/// Returns [`Query`] for the given [`QueryState`], which is used to efficiently
454
/// run queries on the [`World`] by storing and reusing the [`QueryState`].
455
///
456
/// # Panics
457
/// If state is from a different world then self
458
#[inline]
459
pub fn query<'s, D: QueryData, F: QueryFilter>(
460
&mut self,
461
state: &'s mut QueryState<D, F>,
462
) -> Query<'_, 's, D, F> {
463
// SAFETY: We have mutable access to the entire world
464
unsafe { state.query_unchecked(self.world) }
465
}
466
467
/// Gets a mutable reference to the resource of the given type
468
///
469
/// # Panics
470
///
471
/// Panics if the resource does not exist.
472
/// Use [`get_resource_mut`](DeferredWorld::get_resource_mut) instead if you want to handle this case.
473
#[inline]
474
#[track_caller]
475
pub fn resource_mut<R: Resource>(&mut self) -> Mut<'_, R> {
476
match self.get_resource_mut() {
477
Some(x) => x,
478
None => panic!(
479
"Requested resource {} does not exist in the `World`.
480
Did you forget to add it using `app.insert_resource` / `app.init_resource`?
481
Resources are also implicitly added via `app.add_message`,
482
and can be added by plugins.",
483
DebugName::type_name::<R>()
484
),
485
}
486
}
487
488
/// Gets a mutable reference to the resource of the given type if it exists
489
#[inline]
490
pub fn get_resource_mut<R: Resource>(&mut self) -> Option<Mut<'_, R>> {
491
// SAFETY: &mut self ensure that there are no outstanding accesses to the resource
492
unsafe { self.world.get_resource_mut() }
493
}
494
495
/// Gets a mutable reference to a non-send resource of the given type, if it exists.
496
#[deprecated(since = "0.19.0", note = "use DeferredWorld::non_send_mut")]
497
pub fn non_send_resource_mut<R: 'static>(&mut self) -> Mut<'_, R> {
498
self.non_send_mut::<R>()
499
}
500
501
/// Gets a mutable reference to the non-send data of the given type, if it exists.
502
///
503
/// # Panics
504
///
505
/// Panics if the data does not exist.
506
/// Use [`get_non_send_mut`](World::get_non_send_mut) instead if you want to handle this case.
507
///
508
/// This function will panic if it isn't called from the same thread that the data was inserted from.
509
#[inline]
510
#[track_caller]
511
pub fn non_send_mut<R: 'static>(&mut self) -> Mut<'_, R> {
512
match self.get_non_send_mut() {
513
Some(x) => x,
514
None => panic!(
515
"Requested non-send data {} does not exist in the `World`.
516
Did you forget to add it using `app.insert_non_send` / `app.init_non_send`?
517
Non-send data can also be added by plugins.",
518
DebugName::type_name::<R>()
519
),
520
}
521
}
522
523
/// Gets a mutable reference to a non-send resource of the given type, if it exists.
524
/// Otherwise returns `None`.
525
#[deprecated(since = "0.19.0", note = "use DeferredWorld::get_non_send_mut")]
526
pub fn get_non_send_resource_mut<R: 'static>(&mut self) -> Option<Mut<'_, R>> {
527
self.get_non_send_mut::<R>()
528
}
529
530
/// Gets a mutable reference to non-send data of the given type, if it exists.
531
/// Otherwise returns `None`.
532
///
533
/// # Panics
534
/// This function will panic if it isn't called from the same thread that the data was inserted from.
535
#[inline]
536
pub fn get_non_send_mut<R: 'static>(&mut self) -> Option<Mut<'_, R>> {
537
// SAFETY: &mut self ensure that there are no outstanding accesses to the data
538
unsafe { self.world.get_non_send_mut() }
539
}
540
541
/// Writes a [`Message`].
542
/// This method returns the [`MessageId`] of the written `message`,
543
/// or [`None`] if the `message` could not be written.
544
#[inline]
545
pub fn write_message<M: Message>(&mut self, message: M) -> Option<MessageId<M>> {
546
self.write_message_batch(core::iter::once(message))?.next()
547
}
548
549
/// Writes the default value of the [`Message`] of type `E`.
550
/// This method returns the [`MessageId`] of the written `event`,
551
/// or [`None`] if the `event` could not be written.
552
#[inline]
553
pub fn write_message_default<E: Message + Default>(&mut self) -> Option<MessageId<E>> {
554
self.write_message(E::default())
555
}
556
557
/// Writes a batch of [`Message`]s from an iterator.
558
/// This method returns the [IDs](`MessageId`) of the written `events`,
559
/// or [`None`] if the `event` could not be written.
560
#[inline]
561
pub fn write_message_batch<E: Message>(
562
&mut self,
563
events: impl IntoIterator<Item = E>,
564
) -> Option<WriteBatchIds<E>> {
565
let Some(mut events_resource) = self.get_resource_mut::<Messages<E>>() else {
566
log::error!(
567
"Unable to send message `{}`\n\tMessages must be added to the app with `add_message()`\n\thttps://docs.rs/bevy/*/bevy/app/struct.App.html#method.add_message ",
568
DebugName::type_name::<E>()
569
);
570
return None;
571
};
572
Some(events_resource.write_batch(events))
573
}
574
575
/// Gets a pointer to the resource with the id [`ComponentId`] if it exists.
576
/// The returned pointer may be used to modify the resource, as long as the mutable borrow
577
/// of the [`World`] is still valid.
578
///
579
/// **You should prefer to use the typed API [`World::get_resource_mut`] where possible and only
580
/// use this in cases where the actual types are not known at compile time.**
581
#[inline]
582
pub fn get_resource_mut_by_id(&mut self, component_id: ComponentId) -> Option<MutUntyped<'_>> {
583
// SAFETY: &mut self ensure that there are no outstanding accesses to the resource
584
unsafe { self.world.get_resource_mut_by_id(component_id) }
585
}
586
587
/// Gets mutable access to `!Send` data with the id [`ComponentId`] if it exists.
588
/// The returned pointer may be used to modify the data, as long as the mutable borrow
589
/// of the [`World`] is still valid.
590
///
591
/// **You should prefer to use the typed API [`DeferredWorld::get_non_send_mut`] where possible
592
/// and only use this in cases where the actual types are not known at compile time.**
593
///
594
/// # Panics
595
/// This function will panic if it isn't called from the same thread that the data was inserted from.
596
#[inline]
597
pub fn get_non_send_mut_by_id(&mut self, component_id: ComponentId) -> Option<MutUntyped<'_>> {
598
// SAFETY: &mut self ensure that there are no outstanding accesses to the data
599
unsafe { self.world.get_non_send_mut_by_id(component_id) }
600
}
601
602
/// Retrieves a mutable untyped reference to the given `entity`'s [`Component`] of the given [`ComponentId`].
603
/// Returns `None` if the `entity` does not have a [`Component`] of the given type.
604
///
605
/// **You should prefer to use the typed API [`World::get_mut`] where possible and only
606
/// use this in cases where the actual types are not known at compile time.**
607
#[inline]
608
pub fn get_mut_by_id(
609
&mut self,
610
entity: Entity,
611
component_id: ComponentId,
612
) -> Option<MutUntyped<'_>> {
613
self.get_entity_mut(entity)
614
.ok()?
615
.into_mut_by_id(component_id)
616
.ok()
617
}
618
619
/// Triggers all `on_add` hooks for [`ComponentId`] in target.
620
///
621
/// # Safety
622
/// Caller must ensure [`ComponentId`] in target exist in self.
623
#[inline]
624
pub(crate) unsafe fn trigger_on_add(
625
&mut self,
626
archetype: &Archetype,
627
entity: Entity,
628
targets: impl Iterator<Item = ComponentId>,
629
caller: MaybeLocation,
630
) {
631
if archetype.has_add_hook() {
632
for component_id in targets {
633
// SAFETY: Caller ensures that these components exist
634
let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();
635
if let Some(hook) = hooks.on_add {
636
hook(
637
DeferredWorld { world: self.world },
638
HookContext {
639
entity,
640
component_id,
641
caller,
642
relationship_hook_mode: RelationshipHookMode::Run,
643
},
644
);
645
}
646
}
647
}
648
}
649
650
/// Triggers all `on_insert` hooks for [`ComponentId`] in target.
651
///
652
/// # Safety
653
/// Caller must ensure [`ComponentId`] in target exist in self.
654
#[inline]
655
pub(crate) unsafe fn trigger_on_insert(
656
&mut self,
657
archetype: &Archetype,
658
entity: Entity,
659
targets: impl Iterator<Item = ComponentId>,
660
caller: MaybeLocation,
661
relationship_hook_mode: RelationshipHookMode,
662
) {
663
if archetype.has_insert_hook() {
664
for component_id in targets {
665
// SAFETY: Caller ensures that these components exist
666
let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();
667
if let Some(hook) = hooks.on_insert {
668
hook(
669
DeferredWorld { world: self.world },
670
HookContext {
671
entity,
672
component_id,
673
caller,
674
relationship_hook_mode,
675
},
676
);
677
}
678
}
679
}
680
}
681
682
/// Triggers all `on_discard` hooks for [`ComponentId`] in target.
683
///
684
/// # Safety
685
/// Caller must ensure [`ComponentId`] in target exist in self.
686
#[inline]
687
pub(crate) unsafe fn trigger_on_discard(
688
&mut self,
689
archetype: &Archetype,
690
entity: Entity,
691
targets: impl Iterator<Item = ComponentId>,
692
caller: MaybeLocation,
693
relationship_hook_mode: RelationshipHookMode,
694
) {
695
if archetype.has_discard_hook() {
696
for component_id in targets {
697
// SAFETY: Caller ensures that these components exist
698
let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();
699
if let Some(hook) = hooks.on_discard {
700
hook(
701
DeferredWorld { world: self.world },
702
HookContext {
703
entity,
704
component_id,
705
caller,
706
relationship_hook_mode,
707
},
708
);
709
}
710
}
711
}
712
}
713
714
/// Triggers all `on_remove` hooks for [`ComponentId`] in target.
715
///
716
/// # Safety
717
/// Caller must ensure [`ComponentId`] in target exist in self.
718
#[inline]
719
pub(crate) unsafe fn trigger_on_remove(
720
&mut self,
721
archetype: &Archetype,
722
entity: Entity,
723
targets: impl Iterator<Item = ComponentId>,
724
caller: MaybeLocation,
725
) {
726
if archetype.has_remove_hook() {
727
for component_id in targets {
728
// SAFETY: Caller ensures that these components exist
729
let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();
730
if let Some(hook) = hooks.on_remove {
731
hook(
732
DeferredWorld { world: self.world },
733
HookContext {
734
entity,
735
component_id,
736
caller,
737
relationship_hook_mode: RelationshipHookMode::Run,
738
},
739
);
740
}
741
}
742
}
743
}
744
745
/// Triggers all `on_despawn` hooks for [`ComponentId`] in target.
746
///
747
/// # Safety
748
/// Caller must ensure [`ComponentId`] in target exist in self.
749
#[inline]
750
pub(crate) unsafe fn trigger_on_despawn(
751
&mut self,
752
archetype: &Archetype,
753
entity: Entity,
754
targets: impl Iterator<Item = ComponentId>,
755
caller: MaybeLocation,
756
) {
757
if archetype.has_despawn_hook() {
758
for component_id in targets {
759
// SAFETY: Caller ensures that these components exist
760
let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();
761
if let Some(hook) = hooks.on_despawn {
762
hook(
763
DeferredWorld { world: self.world },
764
HookContext {
765
entity,
766
component_id,
767
caller,
768
relationship_hook_mode: RelationshipHookMode::Run,
769
},
770
);
771
}
772
}
773
}
774
}
775
776
/// Triggers all `event` observers for the given `targets`
777
///
778
/// # Safety
779
/// - Caller must ensure `E` is accessible as the type represented by `event_key`
780
#[inline]
781
pub unsafe fn trigger_raw<'a, E: Event>(
782
&mut self,
783
event_key: EventKey,
784
event: &mut E,
785
trigger: &mut E::Trigger<'a>,
786
caller: MaybeLocation,
787
) {
788
// SAFETY: You cannot get a mutable reference to `observers` from `DeferredWorld`
789
let (mut world, observers) = unsafe {
790
let world = self.as_unsafe_world_cell();
791
let observers = world.observers();
792
let Some(observers) = observers.try_get_observers(event_key) else {
793
return;
794
};
795
// SAFETY: The only outstanding reference to world is `observers`
796
(world.into_deferred(), observers)
797
};
798
let context = TriggerContext { event_key, caller };
799
800
// SAFETY:
801
// - `observers` comes from `world`, and corresponds to the `event_key`, as it was looked up above
802
// - trigger_context contains the correct event_key for `event`, as enforced by the call to `trigger_raw`
803
// - This method is being called for an `event` whose `Event::Trigger` matches, as the input trigger is E::Trigger.
804
unsafe {
805
trigger.trigger(world.reborrow(), observers, &context, event);
806
}
807
}
808
809
/// Sends a global [`Event`] without any targets.
810
///
811
/// This will run any [`Observer`] of the given [`Event`] that isn't scoped to specific targets.
812
///
813
/// [`Observer`]: crate::observer::Observer
814
pub fn trigger<'a>(&mut self, event: impl Event<Trigger<'a>: Default>) {
815
self.commands().trigger(event);
816
}
817
818
/// Gets an [`UnsafeWorldCell`] containing the underlying world.
819
///
820
/// # Safety
821
/// - must only be used to make non-structural ECS changes
822
#[inline]
823
pub fn as_unsafe_world_cell(&mut self) -> UnsafeWorldCell<'_> {
824
self.world
825
}
826
}
827
828