Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/relationship/mod.rs
9408 views
1
//! This module provides functionality to link entities to each other using specialized components called "relationships". See the [`Relationship`] trait for more info.
2
3
mod related_methods;
4
mod relationship_query;
5
mod relationship_source_collection;
6
7
use alloc::boxed::Box;
8
use bevy_ptr::Ptr;
9
use core::marker::PhantomData;
10
11
use alloc::format;
12
13
use bevy_utils::prelude::DebugName;
14
pub use related_methods::*;
15
pub use relationship_query::*;
16
pub use relationship_source_collection::*;
17
18
use crate::{
19
component::{Component, ComponentCloneBehavior, Mutable},
20
entity::{ComponentCloneCtx, Entity},
21
error::CommandWithEntity,
22
lifecycle::HookContext,
23
world::{DeferredWorld, EntityWorldMut},
24
};
25
use log::warn;
26
27
/// A [`Component`] on a "source" [`Entity`] that references another target [`Entity`], creating a "relationship" between them. Every [`Relationship`]
28
/// has a corresponding [`RelationshipTarget`] type (and vice-versa), which exists on the "target" entity of a relationship and contains the list of all
29
/// "source" entities that relate to the given "target"
30
///
31
/// The [`Relationship`] component is the "source of truth" and the [`RelationshipTarget`] component reflects that source of truth. When a [`Relationship`]
32
/// component is inserted on an [`Entity`], the corresponding [`RelationshipTarget`] component is immediately inserted on the target component if it does
33
/// not already exist, and the "source" entity is automatically added to the [`RelationshipTarget`] collection (this is done via "component hooks").
34
///
35
/// A common example of a [`Relationship`] is the parent / child relationship. Bevy ECS includes a canonical form of this via the [`ChildOf`](crate::hierarchy::ChildOf)
36
/// [`Relationship`] and the [`Children`](crate::hierarchy::Children) [`RelationshipTarget`].
37
///
38
/// [`Relationship`] and [`RelationshipTarget`] should always be derived via the [`Component`] trait to ensure the hooks are set up properly.
39
///
40
/// ## Derive
41
///
42
/// [`Relationship`] and [`RelationshipTarget`] can only be derived for structs with a single unnamed field, single named field
43
/// or for named structs where one field is annotated with `#[relationship]`.
44
/// If there are additional fields, they must all implement [`Default`].
45
///
46
/// [`RelationshipTarget`] also requires that the relationship field is private to prevent direct mutation,
47
/// ensuring the correctness of relationships.
48
/// ```
49
/// # use bevy_ecs::component::Component;
50
/// # use bevy_ecs::entity::Entity;
51
/// #[derive(Component)]
52
/// #[relationship(relationship_target = Children)]
53
/// pub struct ChildOf {
54
/// #[relationship]
55
/// pub parent: Entity,
56
/// internal: u8,
57
/// };
58
///
59
/// #[derive(Component)]
60
/// #[relationship_target(relationship = ChildOf)]
61
/// pub struct Children(Vec<Entity>);
62
/// ```
63
///
64
/// When deriving [`RelationshipTarget`] you can specify the `#[relationship_target(linked_spawn)]` attribute to
65
/// automatically despawn entities stored in an entity's [`RelationshipTarget`] when that entity is despawned:
66
///
67
/// ```
68
/// # use bevy_ecs::component::Component;
69
/// # use bevy_ecs::entity::Entity;
70
/// #[derive(Component)]
71
/// #[relationship(relationship_target = Children)]
72
/// pub struct ChildOf(pub Entity);
73
///
74
/// #[derive(Component)]
75
/// #[relationship_target(relationship = ChildOf, linked_spawn)]
76
/// pub struct Children(Vec<Entity>);
77
/// ```
78
///
79
/// By default, relationships cannot point to their own entity. If you want to allow self-referential
80
/// relationships, you can use the `allow_self_referential` attribute:
81
///
82
/// ```
83
/// # use bevy_ecs::component::Component;
84
/// # use bevy_ecs::entity::Entity;
85
/// #[derive(Component)]
86
/// #[relationship(relationship_target = PeopleILike, allow_self_referential)]
87
/// pub struct LikedBy(pub Entity);
88
///
89
/// #[derive(Component)]
90
/// #[relationship_target(relationship = LikedBy)]
91
/// pub struct PeopleILike(Vec<Entity>);
92
/// ```
93
pub trait Relationship: Component + Sized {
94
/// The [`Component`] added to the "target" entities of this [`Relationship`], which contains the list of all "source"
95
/// entities that relate to the "target".
96
type RelationshipTarget: RelationshipTarget<Relationship = Self>;
97
98
/// If `true`, a relationship is allowed to point to its own entity.
99
///
100
/// Set this to `true` when self-relationships are semantically valid for your use case,
101
/// such as `Likes(self)`, `EmployedBy(self)`, or a `ColliderOf` relationship where
102
/// a collider can be attached to its own entity.
103
///
104
/// # Warning
105
///
106
/// When `ALLOW_SELF` is `true`, be careful when using recursive traversal methods
107
/// like `iter_ancestors` or `root_ancestor`, as they will loop infinitely if an entity
108
/// points to itself.
109
const ALLOW_SELF_REFERENTIAL: bool = false;
110
111
/// Gets the [`Entity`] ID of the related entity.
112
fn get(&self) -> Entity;
113
114
/// Creates this [`Relationship`] from the given `entity`.
115
fn from(entity: Entity) -> Self;
116
117
/// Changes the current [`Entity`] ID of the entity containing the [`RelationshipTarget`] to another one.
118
///
119
/// This is useful for updating the relationship without overwriting other fields stored in `Self`.
120
///
121
/// # Warning
122
///
123
/// This should generally not be called by user code, as modifying the related entity could invalidate the
124
/// relationship. If this method is used, then the hooks [`on_replace`](Relationship::on_replace) have to
125
/// run before and [`on_insert`](Relationship::on_insert) after it.
126
/// This happens automatically when this method is called with [`EntityWorldMut::modify_component`].
127
///
128
/// Prefer to use regular means of insertions when possible.
129
fn set_risky(&mut self, entity: Entity);
130
131
/// The `on_insert` component hook that maintains the [`Relationship`] / [`RelationshipTarget`] connection.
132
fn on_insert(
133
mut world: DeferredWorld,
134
HookContext {
135
entity,
136
caller,
137
relationship_hook_mode,
138
..
139
}: HookContext,
140
) {
141
match relationship_hook_mode {
142
RelationshipHookMode::Run => {}
143
RelationshipHookMode::Skip => return,
144
RelationshipHookMode::RunIfNotLinked => {
145
if <Self::RelationshipTarget as RelationshipTarget>::LINKED_SPAWN {
146
return;
147
}
148
}
149
}
150
let target_entity = world.entity(entity).get::<Self>().unwrap().get();
151
if !Self::ALLOW_SELF_REFERENTIAL && target_entity == entity {
152
warn!(
153
"{}The {}({target_entity:?}) relationship on entity {entity:?} points to itself. The invalid {} relationship has been removed.\nIf this is intended behavior self-referential relations can be enabled with the allow_self_referential attribute: #[relationship(allow_self_referential)]",
154
caller.map(|location|format!("{location}: ")).unwrap_or_default(),
155
DebugName::type_name::<Self>(),
156
DebugName::type_name::<Self>()
157
);
158
world.commands().entity(entity).remove::<Self>();
159
return;
160
}
161
// For one-to-one relationships, remove existing relationship before adding new one
162
let current_source_to_remove = world
163
.get_entity(target_entity)
164
.ok()
165
.and_then(|target_entity_ref| target_entity_ref.get::<Self::RelationshipTarget>())
166
.and_then(|relationship_target| {
167
relationship_target
168
.collection()
169
.source_to_remove_before_add()
170
});
171
172
if let Some(current_source) = current_source_to_remove {
173
world.commands().entity(current_source).try_remove::<Self>();
174
}
175
176
if let Ok(mut entity_commands) = world.commands().get_entity(target_entity) {
177
// Deferring is necessary for batch mode
178
entity_commands
179
.entry::<Self::RelationshipTarget>()
180
.and_modify(move |mut relationship_target| {
181
relationship_target.collection_mut_risky().add(entity);
182
})
183
.or_insert_with(move || {
184
let mut target = Self::RelationshipTarget::with_capacity(1);
185
target.collection_mut_risky().add(entity);
186
target
187
});
188
} else {
189
warn!(
190
"{}The {}({target_entity:?}) relationship on entity {entity:?} relates to an entity that does not exist. The invalid {} relationship has been removed.",
191
caller.map(|location|format!("{location}: ")).unwrap_or_default(),
192
DebugName::type_name::<Self>(),
193
DebugName::type_name::<Self>()
194
);
195
world.commands().entity(entity).remove::<Self>();
196
}
197
}
198
199
/// The `on_replace` component hook that maintains the [`Relationship`] / [`RelationshipTarget`] connection.
200
// note: think of this as "on_drop"
201
fn on_replace(
202
mut world: DeferredWorld,
203
HookContext {
204
entity,
205
relationship_hook_mode,
206
..
207
}: HookContext,
208
) {
209
match relationship_hook_mode {
210
RelationshipHookMode::Run => {}
211
RelationshipHookMode::Skip => return,
212
RelationshipHookMode::RunIfNotLinked => {
213
if <Self::RelationshipTarget as RelationshipTarget>::LINKED_SPAWN {
214
return;
215
}
216
}
217
}
218
let target_entity = world.entity(entity).get::<Self>().unwrap().get();
219
if let Ok(mut target_entity_mut) = world.get_entity_mut(target_entity)
220
&& let Some(mut relationship_target) =
221
target_entity_mut.get_mut::<Self::RelationshipTarget>()
222
{
223
relationship_target.collection_mut_risky().remove(entity);
224
if relationship_target.len() == 0 {
225
let command = |mut entity: EntityWorldMut| {
226
// this "remove" operation must check emptiness because in the event that an identical
227
// relationship is inserted on top, this despawn would result in the removal of that identical
228
// relationship ... not what we want!
229
if entity
230
.get::<Self::RelationshipTarget>()
231
.is_some_and(RelationshipTarget::is_empty)
232
{
233
entity.remove::<Self::RelationshipTarget>();
234
}
235
};
236
237
world
238
.commands()
239
.queue_silenced(command.with_entity(target_entity));
240
}
241
}
242
}
243
}
244
245
/// The iterator type for the source entities in a [`RelationshipTarget`] collection,
246
/// as defined in the [`RelationshipSourceCollection`] trait.
247
pub type SourceIter<'w, R> =
248
<<R as RelationshipTarget>::Collection as RelationshipSourceCollection>::SourceIter<'w>;
249
250
/// A [`Component`] containing the collection of entities that relate to this [`Entity`] via the associated `Relationship` type.
251
/// See the [`Relationship`] documentation for more information.
252
pub trait RelationshipTarget: Component<Mutability = Mutable> + Sized {
253
/// If this is true, when despawning or cloning (when [linked cloning is enabled](crate::entity::EntityClonerBuilder::linked_cloning)), the related entities targeting this entity will also be despawned or cloned.
254
///
255
/// For example, this is set to `true` for Bevy's built-in parent-child relation, defined by [`ChildOf`](crate::prelude::ChildOf) and [`Children`](crate::prelude::Children).
256
/// This means that when a parent is despawned, any children targeting that parent are also despawned (and the same applies to cloning).
257
///
258
/// To get around this behavior, you can first break the relationship between entities, and *then* despawn or clone.
259
/// This defaults to false when derived.
260
const LINKED_SPAWN: bool;
261
/// The [`Relationship`] that populates this [`RelationshipTarget`] collection.
262
type Relationship: Relationship<RelationshipTarget = Self>;
263
/// The collection type that stores the "source" entities for this [`RelationshipTarget`] component.
264
///
265
/// Check the list of types which implement [`RelationshipSourceCollection`] for the data structures that can be used inside of your component.
266
/// If you need a new collection type, you can implement the [`RelationshipSourceCollection`] trait
267
/// for a type you own which wraps the collection you want to use (to avoid the orphan rule),
268
/// or open an issue on the Bevy repository to request first-party support for your collection type.
269
type Collection: RelationshipSourceCollection;
270
271
/// Returns a reference to the stored [`RelationshipTarget::Collection`].
272
fn collection(&self) -> &Self::Collection;
273
/// Returns a mutable reference to the stored [`RelationshipTarget::Collection`].
274
///
275
/// # Warning
276
/// This should generally not be called by user code, as modifying the internal collection could invalidate the relationship.
277
/// The collection should not contain duplicates.
278
fn collection_mut_risky(&mut self) -> &mut Self::Collection;
279
280
/// Creates a new [`RelationshipTarget`] from the given [`RelationshipTarget::Collection`].
281
///
282
/// # Warning
283
/// This should generally not be called by user code, as constructing the internal collection could invalidate the relationship.
284
/// The collection should not contain duplicates.
285
fn from_collection_risky(collection: Self::Collection) -> Self;
286
287
/// The `on_replace` component hook that maintains the [`Relationship`] / [`RelationshipTarget`] connection.
288
// note: think of this as "on_drop"
289
fn on_replace(
290
mut world: DeferredWorld,
291
HookContext {
292
entity,
293
relationship_hook_mode,
294
..
295
}: HookContext,
296
) {
297
match relationship_hook_mode {
298
RelationshipHookMode::Run => {}
299
// For RelationshipTarget we don't want to run this hook even if it isn't linked, but for Relationship we do.
300
RelationshipHookMode::Skip | RelationshipHookMode::RunIfNotLinked => return,
301
}
302
let (entities, mut commands) = world.entities_and_commands();
303
let relationship_target = entities.get(entity).unwrap().get::<Self>().unwrap();
304
for source_entity in relationship_target.iter() {
305
commands
306
.entity(source_entity)
307
.try_remove::<Self::Relationship>();
308
}
309
}
310
311
/// The `on_despawn` component hook that despawns entities stored in an entity's [`RelationshipTarget`] when
312
/// that entity is despawned.
313
// note: think of this as "on_drop"
314
fn on_despawn(mut world: DeferredWorld, HookContext { entity, .. }: HookContext) {
315
let (entities, mut commands) = world.entities_and_commands();
316
let relationship_target = entities.get(entity).unwrap().get::<Self>().unwrap();
317
for source_entity in relationship_target.iter() {
318
commands.entity(source_entity).try_despawn();
319
}
320
}
321
322
/// Creates this [`RelationshipTarget`] with the given pre-allocated entity capacity.
323
fn with_capacity(capacity: usize) -> Self {
324
let collection =
325
<Self::Collection as RelationshipSourceCollection>::with_capacity(capacity);
326
Self::from_collection_risky(collection)
327
}
328
329
/// Iterates the entities stored in this collection.
330
#[inline]
331
fn iter(&self) -> SourceIter<'_, Self> {
332
self.collection().iter()
333
}
334
335
/// Returns the number of entities in this collection.
336
#[inline]
337
fn len(&self) -> usize {
338
self.collection().len()
339
}
340
341
/// Returns true if this entity collection is empty.
342
#[inline]
343
fn is_empty(&self) -> bool {
344
self.collection().is_empty()
345
}
346
}
347
348
/// The "clone behavior" for [`RelationshipTarget`]. The [`RelationshipTarget`] will be populated with the proper components
349
/// when the corresponding [`Relationship`] sources of truth are inserted. Cloning the actual entities
350
/// in the original [`RelationshipTarget`] would result in duplicates, so we don't do that!
351
///
352
/// This will also queue up clones of the relationship sources if the [`EntityCloner`](crate::entity::EntityCloner) is configured
353
/// to spawn recursively.
354
pub fn clone_relationship_target<T: RelationshipTarget>(
355
component: &T,
356
cloned: &mut T,
357
context: &mut ComponentCloneCtx,
358
) {
359
if context.linked_cloning() && T::LINKED_SPAWN {
360
let collection = cloned.collection_mut_risky();
361
for entity in component.iter() {
362
collection.add(entity);
363
context.queue_entity_clone(entity);
364
}
365
} else if context.moving() {
366
let target = context.target();
367
let collection = cloned.collection_mut_risky();
368
for entity in component.iter() {
369
collection.add(entity);
370
context.queue_deferred(move |world, _mapper| {
371
// We don't want relationships hooks to run because we are manually constructing the collection here
372
_ = DeferredWorld::from(world)
373
.modify_component_with_relationship_hook_mode::<T::Relationship, ()>(
374
entity,
375
RelationshipHookMode::Skip,
376
|r| r.set_risky(target),
377
);
378
});
379
}
380
}
381
}
382
383
/// Configures the conditions under which the Relationship insert/replace hooks will be run.
384
#[derive(Copy, Clone, Debug)]
385
pub enum RelationshipHookMode {
386
/// Relationship insert/replace hooks will always run
387
Run,
388
/// Relationship insert/replace hooks will run if [`RelationshipTarget::LINKED_SPAWN`] is false
389
RunIfNotLinked,
390
/// Relationship insert/replace hooks will always be skipped
391
Skip,
392
}
393
394
/// Wrapper for components clone specialization using autoderef.
395
#[doc(hidden)]
396
pub struct RelationshipCloneBehaviorSpecialization<T>(PhantomData<T>);
397
398
impl<T> Default for RelationshipCloneBehaviorSpecialization<T> {
399
fn default() -> Self {
400
Self(PhantomData)
401
}
402
}
403
404
/// Base trait for relationship clone specialization using autoderef.
405
#[doc(hidden)]
406
pub trait RelationshipCloneBehaviorBase {
407
fn default_clone_behavior(&self) -> ComponentCloneBehavior;
408
}
409
410
impl<C> RelationshipCloneBehaviorBase for RelationshipCloneBehaviorSpecialization<C> {
411
fn default_clone_behavior(&self) -> ComponentCloneBehavior {
412
// Relationships currently must have `Clone`/`Reflect`-based handler for cloning/moving logic to properly work.
413
ComponentCloneBehavior::Ignore
414
}
415
}
416
417
/// Specialized trait for relationship clone specialization using autoderef.
418
#[doc(hidden)]
419
pub trait RelationshipCloneBehaviorViaReflect {
420
fn default_clone_behavior(&self) -> ComponentCloneBehavior;
421
}
422
423
#[cfg(feature = "bevy_reflect")]
424
impl<C: Relationship + bevy_reflect::Reflect> RelationshipCloneBehaviorViaReflect
425
for &RelationshipCloneBehaviorSpecialization<C>
426
{
427
fn default_clone_behavior(&self) -> ComponentCloneBehavior {
428
ComponentCloneBehavior::reflect()
429
}
430
}
431
432
/// Specialized trait for relationship clone specialization using autoderef.
433
#[doc(hidden)]
434
pub trait RelationshipCloneBehaviorViaClone {
435
fn default_clone_behavior(&self) -> ComponentCloneBehavior;
436
}
437
438
impl<C: Relationship + Clone> RelationshipCloneBehaviorViaClone
439
for &&RelationshipCloneBehaviorSpecialization<C>
440
{
441
fn default_clone_behavior(&self) -> ComponentCloneBehavior {
442
ComponentCloneBehavior::clone::<C>()
443
}
444
}
445
446
/// Specialized trait for relationship target clone specialization using autoderef.
447
#[doc(hidden)]
448
pub trait RelationshipTargetCloneBehaviorViaReflect {
449
fn default_clone_behavior(&self) -> ComponentCloneBehavior;
450
}
451
452
#[cfg(feature = "bevy_reflect")]
453
impl<C: RelationshipTarget + bevy_reflect::Reflect + bevy_reflect::TypePath>
454
RelationshipTargetCloneBehaviorViaReflect for &&&RelationshipCloneBehaviorSpecialization<C>
455
{
456
fn default_clone_behavior(&self) -> ComponentCloneBehavior {
457
ComponentCloneBehavior::Custom(|source, context| {
458
if let Some(component) = source.read::<C>()
459
&& let Ok(mut cloned) = component.reflect_clone_and_take::<C>()
460
{
461
cloned.collection_mut_risky().clear();
462
clone_relationship_target(component, &mut cloned, context);
463
context.write_target_component(cloned);
464
}
465
})
466
}
467
}
468
469
/// Specialized trait for relationship target clone specialization using autoderef.
470
#[doc(hidden)]
471
pub trait RelationshipTargetCloneBehaviorViaClone {
472
fn default_clone_behavior(&self) -> ComponentCloneBehavior;
473
}
474
475
impl<C: RelationshipTarget + Clone> RelationshipTargetCloneBehaviorViaClone
476
for &&&&RelationshipCloneBehaviorSpecialization<C>
477
{
478
fn default_clone_behavior(&self) -> ComponentCloneBehavior {
479
ComponentCloneBehavior::Custom(|source, context| {
480
if let Some(component) = source.read::<C>() {
481
let mut cloned = component.clone();
482
cloned.collection_mut_risky().clear();
483
clone_relationship_target(component, &mut cloned, context);
484
context.write_target_component(cloned);
485
}
486
})
487
}
488
}
489
490
/// We know there's no additional data on Children, so this handler is an optimization to avoid cloning the entire Collection.
491
#[doc(hidden)]
492
pub trait RelationshipTargetCloneBehaviorHierarchy {
493
fn default_clone_behavior(&self) -> ComponentCloneBehavior;
494
}
495
496
impl RelationshipTargetCloneBehaviorHierarchy
497
for &&&&&RelationshipCloneBehaviorSpecialization<crate::hierarchy::Children>
498
{
499
fn default_clone_behavior(&self) -> ComponentCloneBehavior {
500
ComponentCloneBehavior::Custom(|source, context| {
501
if let Some(component) = source.read::<crate::hierarchy::Children>() {
502
let mut cloned = crate::hierarchy::Children::with_capacity(component.len());
503
clone_relationship_target(component, &mut cloned, context);
504
context.write_target_component(cloned);
505
}
506
})
507
}
508
}
509
510
/// This enum describes a way to access the entities of [`Relationship`] and [`RelationshipTarget`] components
511
/// in a type-erased context.
512
#[derive(Debug, Clone, Copy)]
513
pub enum RelationshipAccessor {
514
/// This component is a [`Relationship`].
515
Relationship {
516
/// Offset of the field containing [`Entity`] from the base of the component.
517
///
518
/// Dynamic equivalent of [`Relationship::get`].
519
entity_field_offset: usize,
520
/// Value of [`RelationshipTarget::LINKED_SPAWN`] for the [`Relationship::RelationshipTarget`] of this [`Relationship`].
521
linked_spawn: bool,
522
},
523
/// This component is a [`RelationshipTarget`].
524
RelationshipTarget {
525
/// Function that returns an iterator over all [`Entity`]s of this [`RelationshipTarget`]'s collection.
526
///
527
/// Dynamic equivalent of [`RelationshipTarget::iter`].
528
/// # Safety
529
/// Passed pointer must point to the value of the same component as the one that this accessor was registered to.
530
iter: for<'a> unsafe fn(Ptr<'a>) -> Box<dyn Iterator<Item = Entity> + 'a>,
531
/// Value of [`RelationshipTarget::LINKED_SPAWN`] of this [`RelationshipTarget`].
532
linked_spawn: bool,
533
},
534
}
535
536
/// A type-safe convenience wrapper over [`RelationshipAccessor`].
537
pub struct ComponentRelationshipAccessor<C: ?Sized> {
538
pub(crate) accessor: RelationshipAccessor,
539
phantom: PhantomData<C>,
540
}
541
542
impl<C> ComponentRelationshipAccessor<C> {
543
/// Create a new [`ComponentRelationshipAccessor`] for a [`Relationship`] component.
544
/// # Safety
545
/// `entity_field_offset` should be the offset from the base of this component and point to a field that stores value of type [`Entity`].
546
/// This value can be obtained using the [`core::mem::offset_of`] macro.
547
pub unsafe fn relationship(entity_field_offset: usize) -> Self
548
where
549
C: Relationship,
550
{
551
Self {
552
accessor: RelationshipAccessor::Relationship {
553
entity_field_offset,
554
linked_spawn: C::RelationshipTarget::LINKED_SPAWN,
555
},
556
phantom: Default::default(),
557
}
558
}
559
560
/// Create a new [`ComponentRelationshipAccessor`] for a [`RelationshipTarget`] component.
561
pub fn relationship_target() -> Self
562
where
563
C: RelationshipTarget,
564
{
565
Self {
566
accessor: RelationshipAccessor::RelationshipTarget {
567
// Safety: caller ensures that `ptr` is of type `C`.
568
iter: |ptr| unsafe { Box::new(RelationshipTarget::iter(ptr.deref::<C>())) },
569
linked_spawn: C::LINKED_SPAWN,
570
},
571
phantom: Default::default(),
572
}
573
}
574
}
575
576
#[cfg(test)]
577
mod tests {
578
use core::marker::PhantomData;
579
580
use crate::prelude::{ChildOf, Children};
581
use crate::relationship::{Relationship, RelationshipAccessor};
582
use crate::world::World;
583
use crate::{component::Component, entity::Entity};
584
use alloc::vec::Vec;
585
586
#[test]
587
fn custom_relationship() {
588
#[derive(Component)]
589
#[relationship(relationship_target = LikedBy)]
590
struct Likes(pub Entity);
591
592
#[derive(Component)]
593
#[relationship_target(relationship = Likes)]
594
struct LikedBy(Vec<Entity>);
595
596
let mut world = World::new();
597
let a = world.spawn_empty().id();
598
let b = world.spawn(Likes(a)).id();
599
let c = world.spawn(Likes(a)).id();
600
assert_eq!(world.entity(a).get::<LikedBy>().unwrap().0, &[b, c]);
601
}
602
603
#[test]
604
fn self_relationship_fails_by_default() {
605
#[derive(Component)]
606
#[relationship(relationship_target = RelTarget)]
607
struct Rel(Entity);
608
609
#[derive(Component)]
610
#[relationship_target(relationship = Rel)]
611
struct RelTarget(Vec<Entity>);
612
613
let mut world = World::new();
614
let a = world.spawn_empty().id();
615
world.entity_mut(a).insert(Rel(a));
616
assert!(!world.entity(a).contains::<Rel>());
617
assert!(!world.entity(a).contains::<RelTarget>());
618
}
619
620
#[test]
621
fn self_relationship_succeeds_with_allow_self_referential() {
622
#[derive(Component)]
623
#[relationship(relationship_target = RelTarget, allow_self_referential)]
624
struct Rel(Entity);
625
626
#[derive(Component)]
627
#[relationship_target(relationship = Rel)]
628
struct RelTarget(Vec<Entity>);
629
630
let mut world = World::new();
631
let a = world.spawn_empty().id();
632
world.entity_mut(a).insert(Rel(a));
633
assert!(world.entity(a).contains::<Rel>());
634
assert!(world.entity(a).contains::<RelTarget>());
635
assert_eq!(world.entity(a).get::<Rel>().unwrap().get(), a);
636
assert_eq!(&*world.entity(a).get::<RelTarget>().unwrap().0, &[a]);
637
}
638
639
#[test]
640
fn self_relationship_removal_with_allow_self_referential() {
641
#[derive(Component)]
642
#[relationship(relationship_target = RelTarget, allow_self_referential)]
643
struct Rel(Entity);
644
645
#[derive(Component)]
646
#[relationship_target(relationship = Rel)]
647
struct RelTarget(Vec<Entity>);
648
649
let mut world = World::new();
650
let a = world.spawn_empty().id();
651
world.entity_mut(a).insert(Rel(a));
652
assert!(world.entity(a).contains::<Rel>());
653
assert!(world.entity(a).contains::<RelTarget>());
654
655
// Remove the relationship and verify cleanup
656
world.entity_mut(a).remove::<Rel>();
657
assert!(!world.entity(a).contains::<Rel>());
658
assert!(!world.entity(a).contains::<RelTarget>());
659
}
660
661
#[test]
662
fn relationship_with_missing_target_fails() {
663
#[derive(Component)]
664
#[relationship(relationship_target = RelTarget)]
665
struct Rel(Entity);
666
667
#[derive(Component)]
668
#[relationship_target(relationship = Rel)]
669
struct RelTarget(Vec<Entity>);
670
671
let mut world = World::new();
672
let a = world.spawn_empty().id();
673
world.despawn(a);
674
let b = world.spawn(Rel(a)).id();
675
assert!(!world.entity(b).contains::<Rel>());
676
assert!(!world.entity(b).contains::<RelTarget>());
677
}
678
679
#[test]
680
fn relationship_with_multiple_non_target_fields_compiles() {
681
#[expect(
682
dead_code,
683
reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
684
)]
685
#[derive(Component)]
686
#[relationship(relationship_target=Target)]
687
struct Source {
688
#[relationship]
689
target: Entity,
690
foo: u8,
691
bar: u8,
692
}
693
694
#[expect(
695
dead_code,
696
reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
697
)]
698
#[derive(Component)]
699
#[relationship_target(relationship=Source)]
700
struct Target(Vec<Entity>);
701
702
// No assert necessary, looking to make sure compilation works with the macros
703
}
704
#[test]
705
fn relationship_target_with_multiple_non_target_fields_compiles() {
706
#[expect(
707
dead_code,
708
reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
709
)]
710
#[derive(Component)]
711
#[relationship(relationship_target=Target)]
712
struct Source(Entity);
713
714
#[expect(
715
dead_code,
716
reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
717
)]
718
#[derive(Component)]
719
#[relationship_target(relationship=Source)]
720
struct Target {
721
#[relationship]
722
target: Vec<Entity>,
723
foo: u8,
724
bar: u8,
725
}
726
727
// No assert necessary, looking to make sure compilation works with the macros
728
}
729
730
#[test]
731
fn relationship_with_multiple_unnamed_non_target_fields_compiles() {
732
#[expect(
733
dead_code,
734
reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
735
)]
736
#[derive(Component)]
737
#[relationship(relationship_target=Target<T>)]
738
struct Source<T: Send + Sync + 'static>(#[relationship] Entity, PhantomData<T>);
739
740
#[expect(
741
dead_code,
742
reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
743
)]
744
#[derive(Component)]
745
#[relationship_target(relationship=Source<T>)]
746
struct Target<T: Send + Sync + 'static>(#[relationship] Vec<Entity>, PhantomData<T>);
747
748
// No assert necessary, looking to make sure compilation works with the macros
749
}
750
751
#[test]
752
fn parent_child_relationship_with_custom_relationship() {
753
#[derive(Component)]
754
#[relationship(relationship_target = RelTarget)]
755
struct Rel(Entity);
756
757
#[derive(Component)]
758
#[relationship_target(relationship = Rel)]
759
struct RelTarget(Entity);
760
761
let mut world = World::new();
762
763
// Rel on Parent
764
// Despawn Parent
765
let mut commands = world.commands();
766
let child = commands.spawn_empty().id();
767
let parent = commands.spawn(Rel(child)).add_child(child).id();
768
commands.entity(parent).despawn();
769
world.flush();
770
771
assert!(world.get_entity(child).is_err());
772
assert!(world.get_entity(parent).is_err());
773
774
// Rel on Parent
775
// Despawn Child
776
let mut commands = world.commands();
777
let child = commands.spawn_empty().id();
778
let parent = commands.spawn(Rel(child)).add_child(child).id();
779
commands.entity(child).despawn();
780
world.flush();
781
782
assert!(world.get_entity(child).is_err());
783
assert!(!world.entity(parent).contains::<Rel>());
784
785
// Rel on Child
786
// Despawn Parent
787
let mut commands = world.commands();
788
let parent = commands.spawn_empty().id();
789
let child = commands.spawn((ChildOf(parent), Rel(parent))).id();
790
commands.entity(parent).despawn();
791
world.flush();
792
793
assert!(world.get_entity(child).is_err());
794
assert!(world.get_entity(parent).is_err());
795
796
// Rel on Child
797
// Despawn Child
798
let mut commands = world.commands();
799
let parent = commands.spawn_empty().id();
800
let child = commands.spawn((ChildOf(parent), Rel(parent))).id();
801
commands.entity(child).despawn();
802
world.flush();
803
804
assert!(world.get_entity(child).is_err());
805
assert!(!world.entity(parent).contains::<RelTarget>());
806
}
807
808
#[test]
809
fn spawn_batch_with_relationship() {
810
let mut world = World::new();
811
let parent = world.spawn_empty().id();
812
let children = world
813
.spawn_batch((0..10).map(|_| ChildOf(parent)))
814
.collect::<Vec<_>>();
815
816
for &child in &children {
817
assert!(world
818
.get::<ChildOf>(child)
819
.is_some_and(|child_of| child_of.parent() == parent));
820
}
821
assert!(world
822
.get::<Children>(parent)
823
.is_some_and(|children| children.len() == 10));
824
}
825
826
#[test]
827
fn insert_batch_with_relationship() {
828
let mut world = World::new();
829
let parent = world.spawn_empty().id();
830
let child = world.spawn_empty().id();
831
world.insert_batch([(child, ChildOf(parent))]);
832
world.flush();
833
834
assert!(world.get::<ChildOf>(child).is_some());
835
assert!(world.get::<Children>(parent).is_some());
836
}
837
838
#[test]
839
fn dynamically_traverse_hierarchy() {
840
let mut world = World::new();
841
let child_of_id = world.register_component::<ChildOf>();
842
let children_id = world.register_component::<Children>();
843
844
let parent = world.spawn_empty().id();
845
let child = world.spawn_empty().id();
846
world.entity_mut(child).insert(ChildOf(parent));
847
world.flush();
848
849
let children_ptr = world.get_by_id(parent, children_id).unwrap();
850
let RelationshipAccessor::RelationshipTarget { iter, .. } = world
851
.components()
852
.get_info(children_id)
853
.unwrap()
854
.relationship_accessor()
855
.unwrap()
856
else {
857
unreachable!()
858
};
859
// Safety: `children_ptr` contains value of the same type as the one this accessor was registered for.
860
let children: Vec<_> = unsafe { iter(children_ptr).collect() };
861
assert_eq!(children, alloc::vec![child]);
862
863
let child_of_ptr = world.get_by_id(child, child_of_id).unwrap();
864
let RelationshipAccessor::Relationship {
865
entity_field_offset,
866
..
867
} = world
868
.components()
869
.get_info(child_of_id)
870
.unwrap()
871
.relationship_accessor()
872
.unwrap()
873
else {
874
unreachable!()
875
};
876
// Safety:
877
// - offset is in bounds, aligned and has the same lifetime as the original pointer.
878
// - value at offset is guaranteed to be a valid Entity
879
let child_of_entity: Entity =
880
unsafe { *child_of_ptr.byte_add(*entity_field_offset).deref() };
881
assert_eq!(child_of_entity, parent);
882
}
883
}
884
885