1mod related_methods;
4mod relationship_query;
5mod relationship_source_collection;
6
7use core::marker::PhantomData;
8
9use alloc::format;
10
11use bevy_utils::prelude::DebugName;
12pub use related_methods::*;
13pub use relationship_query::*;
14pub use relationship_source_collection::*;
15
16use crate::{
17 component::{Component, ComponentCloneBehavior, Mutable},
18 entity::{ComponentCloneCtx, Entity},
19 error::CommandWithEntity,
20 lifecycle::HookContext,
21 world::{DeferredWorld, EntityWorldMut},
22};
23use log::warn;
24
25pub trait Relationship: Component + Sized {
77 type RelationshipTarget: RelationshipTarget<Relationship = Self>;
80
81 fn get(&self) -> Entity;
83
84 fn from(entity: Entity) -> Self;
86
87 fn set_risky(&mut self, entity: Entity);
100
101 fn on_insert(
103 mut world: DeferredWorld,
104 HookContext {
105 entity,
106 caller,
107 relationship_hook_mode,
108 ..
109 }: HookContext,
110 ) {
111 match relationship_hook_mode {
112 RelationshipHookMode::Run => {}
113 RelationshipHookMode::Skip => return,
114 RelationshipHookMode::RunIfNotLinked => {
115 if <Self::RelationshipTarget as RelationshipTarget>::LINKED_SPAWN {
116 return;
117 }
118 }
119 }
120 let target_entity = world.entity(entity).get::<Self>().unwrap().get();
121 if target_entity == entity {
122 warn!(
123 "{}The {}({target_entity:?}) relationship on entity {entity:?} points to itself. The invalid {} relationship has been removed.",
124 caller.map(|location|format!("{location}: ")).unwrap_or_default(),
125 DebugName::type_name::<Self>(),
126 DebugName::type_name::<Self>()
127 );
128 world.commands().entity(entity).remove::<Self>();
129 return;
130 }
131 let current_source_to_remove = world
133 .get_entity(target_entity)
134 .ok()
135 .and_then(|target_entity_ref| target_entity_ref.get::<Self::RelationshipTarget>())
136 .and_then(|relationship_target| {
137 relationship_target
138 .collection()
139 .source_to_remove_before_add()
140 });
141
142 if let Some(current_source) = current_source_to_remove {
143 world.commands().entity(current_source).try_remove::<Self>();
144 }
145
146 if let Ok(mut entity_commands) = world.commands().get_entity(target_entity) {
147 entity_commands
149 .entry::<Self::RelationshipTarget>()
150 .and_modify(move |mut relationship_target| {
151 relationship_target.collection_mut_risky().add(entity);
152 })
153 .or_insert_with(move || {
154 let mut target = Self::RelationshipTarget::with_capacity(1);
155 target.collection_mut_risky().add(entity);
156 target
157 });
158 } else {
159 warn!(
160 "{}The {}({target_entity:?}) relationship on entity {entity:?} relates to an entity that does not exist. The invalid {} relationship has been removed.",
161 caller.map(|location|format!("{location}: ")).unwrap_or_default(),
162 DebugName::type_name::<Self>(),
163 DebugName::type_name::<Self>()
164 );
165 world.commands().entity(entity).remove::<Self>();
166 }
167 }
168
169 fn on_replace(
172 mut world: DeferredWorld,
173 HookContext {
174 entity,
175 relationship_hook_mode,
176 ..
177 }: HookContext,
178 ) {
179 match relationship_hook_mode {
180 RelationshipHookMode::Run => {}
181 RelationshipHookMode::Skip => return,
182 RelationshipHookMode::RunIfNotLinked => {
183 if <Self::RelationshipTarget as RelationshipTarget>::LINKED_SPAWN {
184 return;
185 }
186 }
187 }
188 let target_entity = world.entity(entity).get::<Self>().unwrap().get();
189 if let Ok(mut target_entity_mut) = world.get_entity_mut(target_entity) {
190 if let Some(mut relationship_target) =
191 target_entity_mut.get_mut::<Self::RelationshipTarget>()
192 {
193 relationship_target.collection_mut_risky().remove(entity);
194 if relationship_target.len() == 0 {
195 let command = |mut entity: EntityWorldMut| {
196 if entity
200 .get::<Self::RelationshipTarget>()
201 .is_some_and(RelationshipTarget::is_empty)
202 {
203 entity.remove::<Self::RelationshipTarget>();
204 }
205 };
206
207 world
208 .commands()
209 .queue_silenced(command.with_entity(target_entity));
210 }
211 }
212 }
213 }
214}
215
216pub type SourceIter<'w, R> =
219 <<R as RelationshipTarget>::Collection as RelationshipSourceCollection>::SourceIter<'w>;
220
221pub trait RelationshipTarget: Component<Mutability = Mutable> + Sized {
224 const LINKED_SPAWN: bool;
232 type Relationship: Relationship<RelationshipTarget = Self>;
234 type Collection: RelationshipSourceCollection;
241
242 fn collection(&self) -> &Self::Collection;
244 fn collection_mut_risky(&mut self) -> &mut Self::Collection;
250
251 fn from_collection_risky(collection: Self::Collection) -> Self;
257
258 fn on_replace(
261 mut world: DeferredWorld,
262 HookContext {
263 entity,
264 relationship_hook_mode,
265 ..
266 }: HookContext,
267 ) {
268 match relationship_hook_mode {
269 RelationshipHookMode::Run => {}
270 RelationshipHookMode::Skip | RelationshipHookMode::RunIfNotLinked => return,
272 }
273 let (entities, mut commands) = world.entities_and_commands();
274 let relationship_target = entities.get(entity).unwrap().get::<Self>().unwrap();
275 for source_entity in relationship_target.iter() {
276 commands
277 .entity(source_entity)
278 .try_remove::<Self::Relationship>();
279 }
280 }
281
282 fn on_despawn(mut world: DeferredWorld, HookContext { entity, .. }: HookContext) {
286 let (entities, mut commands) = world.entities_and_commands();
287 let relationship_target = entities.get(entity).unwrap().get::<Self>().unwrap();
288 for source_entity in relationship_target.iter() {
289 commands.entity(source_entity).try_despawn();
290 }
291 }
292
293 fn with_capacity(capacity: usize) -> Self {
295 let collection =
296 <Self::Collection as RelationshipSourceCollection>::with_capacity(capacity);
297 Self::from_collection_risky(collection)
298 }
299
300 #[inline]
302 fn iter(&self) -> SourceIter<'_, Self> {
303 self.collection().iter()
304 }
305
306 #[inline]
308 fn len(&self) -> usize {
309 self.collection().len()
310 }
311
312 #[inline]
314 fn is_empty(&self) -> bool {
315 self.collection().is_empty()
316 }
317}
318
319pub fn clone_relationship_target<T: RelationshipTarget>(
326 component: &T,
327 cloned: &mut T,
328 context: &mut ComponentCloneCtx,
329) {
330 if context.linked_cloning() && T::LINKED_SPAWN {
331 let collection = cloned.collection_mut_risky();
332 for entity in component.iter() {
333 collection.add(entity);
334 context.queue_entity_clone(entity);
335 }
336 } else if context.moving() {
337 let target = context.target();
338 let collection = cloned.collection_mut_risky();
339 for entity in component.iter() {
340 collection.add(entity);
341 context.queue_deferred(move |world, _mapper| {
342 _ = DeferredWorld::from(world)
344 .modify_component_with_relationship_hook_mode::<T::Relationship, ()>(
345 entity,
346 RelationshipHookMode::Skip,
347 |r| r.set_risky(target),
348 );
349 });
350 }
351 }
352}
353
354#[derive(Copy, Clone, Debug)]
356pub enum RelationshipHookMode {
357 Run,
359 RunIfNotLinked,
361 Skip,
363}
364
365#[doc(hidden)]
367pub struct RelationshipCloneBehaviorSpecialization<T>(PhantomData<T>);
368
369impl<T> Default for RelationshipCloneBehaviorSpecialization<T> {
370 fn default() -> Self {
371 Self(PhantomData)
372 }
373}
374
375#[doc(hidden)]
377pub trait RelationshipCloneBehaviorBase {
378 fn default_clone_behavior(&self) -> ComponentCloneBehavior;
379}
380
381impl<C> RelationshipCloneBehaviorBase for RelationshipCloneBehaviorSpecialization<C> {
382 fn default_clone_behavior(&self) -> ComponentCloneBehavior {
383 ComponentCloneBehavior::Ignore
385 }
386}
387
388#[doc(hidden)]
390pub trait RelationshipCloneBehaviorViaReflect {
391 fn default_clone_behavior(&self) -> ComponentCloneBehavior;
392}
393
394#[cfg(feature = "bevy_reflect")]
395impl<C: Relationship + bevy_reflect::Reflect> RelationshipCloneBehaviorViaReflect
396 for &RelationshipCloneBehaviorSpecialization<C>
397{
398 fn default_clone_behavior(&self) -> ComponentCloneBehavior {
399 ComponentCloneBehavior::reflect()
400 }
401}
402
403#[doc(hidden)]
405pub trait RelationshipCloneBehaviorViaClone {
406 fn default_clone_behavior(&self) -> ComponentCloneBehavior;
407}
408
409impl<C: Relationship + Clone> RelationshipCloneBehaviorViaClone
410 for &&RelationshipCloneBehaviorSpecialization<C>
411{
412 fn default_clone_behavior(&self) -> ComponentCloneBehavior {
413 ComponentCloneBehavior::clone::<C>()
414 }
415}
416
417#[doc(hidden)]
419pub trait RelationshipTargetCloneBehaviorViaReflect {
420 fn default_clone_behavior(&self) -> ComponentCloneBehavior;
421}
422
423#[cfg(feature = "bevy_reflect")]
424impl<C: RelationshipTarget + bevy_reflect::Reflect + bevy_reflect::TypePath>
425 RelationshipTargetCloneBehaviorViaReflect for &&&RelationshipCloneBehaviorSpecialization<C>
426{
427 fn default_clone_behavior(&self) -> ComponentCloneBehavior {
428 ComponentCloneBehavior::Custom(|source, context| {
429 if let Some(component) = source.read::<C>()
430 && let Ok(mut cloned) = component.reflect_clone_and_take::<C>()
431 {
432 cloned.collection_mut_risky().clear();
433 clone_relationship_target(component, &mut cloned, context);
434 context.write_target_component(cloned);
435 }
436 })
437 }
438}
439
440#[doc(hidden)]
442pub trait RelationshipTargetCloneBehaviorViaClone {
443 fn default_clone_behavior(&self) -> ComponentCloneBehavior;
444}
445
446impl<C: RelationshipTarget + Clone> RelationshipTargetCloneBehaviorViaClone
447 for &&&&RelationshipCloneBehaviorSpecialization<C>
448{
449 fn default_clone_behavior(&self) -> ComponentCloneBehavior {
450 ComponentCloneBehavior::Custom(|source, context| {
451 if let Some(component) = source.read::<C>() {
452 let mut cloned = component.clone();
453 cloned.collection_mut_risky().clear();
454 clone_relationship_target(component, &mut cloned, context);
455 context.write_target_component(cloned);
456 }
457 })
458 }
459}
460
461#[doc(hidden)]
463pub trait RelationshipTargetCloneBehaviorHierarchy {
464 fn default_clone_behavior(&self) -> ComponentCloneBehavior;
465}
466
467impl RelationshipTargetCloneBehaviorHierarchy
468 for &&&&&RelationshipCloneBehaviorSpecialization<crate::hierarchy::Children>
469{
470 fn default_clone_behavior(&self) -> ComponentCloneBehavior {
471 ComponentCloneBehavior::Custom(|source, context| {
472 if let Some(component) = source.read::<crate::hierarchy::Children>() {
473 let mut cloned = crate::hierarchy::Children::with_capacity(component.len());
474 clone_relationship_target(component, &mut cloned, context);
475 context.write_target_component(cloned);
476 }
477 })
478 }
479}
480
481#[cfg(test)]
482mod tests {
483 use core::marker::PhantomData;
484
485 use crate::prelude::{ChildOf, Children};
486 use crate::world::World;
487 use crate::{component::Component, entity::Entity};
488 use alloc::vec::Vec;
489
490 #[test]
491 fn custom_relationship() {
492 #[derive(Component)]
493 #[relationship(relationship_target = LikedBy)]
494 struct Likes(pub Entity);
495
496 #[derive(Component)]
497 #[relationship_target(relationship = Likes)]
498 struct LikedBy(Vec<Entity>);
499
500 let mut world = World::new();
501 let a = world.spawn_empty().id();
502 let b = world.spawn(Likes(a)).id();
503 let c = world.spawn(Likes(a)).id();
504 assert_eq!(world.entity(a).get::<LikedBy>().unwrap().0, &[b, c]);
505 }
506
507 #[test]
508 fn self_relationship_fails() {
509 #[derive(Component)]
510 #[relationship(relationship_target = RelTarget)]
511 struct Rel(Entity);
512
513 #[derive(Component)]
514 #[relationship_target(relationship = Rel)]
515 struct RelTarget(Vec<Entity>);
516
517 let mut world = World::new();
518 let a = world.spawn_empty().id();
519 world.entity_mut(a).insert(Rel(a));
520 assert!(!world.entity(a).contains::<Rel>());
521 assert!(!world.entity(a).contains::<RelTarget>());
522 }
523
524 #[test]
525 fn relationship_with_missing_target_fails() {
526 #[derive(Component)]
527 #[relationship(relationship_target = RelTarget)]
528 struct Rel(Entity);
529
530 #[derive(Component)]
531 #[relationship_target(relationship = Rel)]
532 struct RelTarget(Vec<Entity>);
533
534 let mut world = World::new();
535 let a = world.spawn_empty().id();
536 world.despawn(a);
537 let b = world.spawn(Rel(a)).id();
538 assert!(!world.entity(b).contains::<Rel>());
539 assert!(!world.entity(b).contains::<RelTarget>());
540 }
541
542 #[test]
543 fn relationship_with_multiple_non_target_fields_compiles() {
544 #[expect(
545 dead_code,
546 reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
547 )]
548 #[derive(Component)]
549 #[relationship(relationship_target=Target)]
550 struct Source {
551 #[relationship]
552 target: Entity,
553 foo: u8,
554 bar: u8,
555 }
556
557 #[expect(
558 dead_code,
559 reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
560 )]
561 #[derive(Component)]
562 #[relationship_target(relationship=Source)]
563 struct Target(Vec<Entity>);
564
565 }
567 #[test]
568 fn relationship_target_with_multiple_non_target_fields_compiles() {
569 #[expect(
570 dead_code,
571 reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
572 )]
573 #[derive(Component)]
574 #[relationship(relationship_target=Target)]
575 struct Source(Entity);
576
577 #[expect(
578 dead_code,
579 reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
580 )]
581 #[derive(Component)]
582 #[relationship_target(relationship=Source)]
583 struct Target {
584 #[relationship]
585 target: Vec<Entity>,
586 foo: u8,
587 bar: u8,
588 }
589
590 }
592
593 #[test]
594 fn relationship_with_multiple_unnamed_non_target_fields_compiles() {
595 #[expect(
596 dead_code,
597 reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
598 )]
599 #[derive(Component)]
600 #[relationship(relationship_target=Target<T>)]
601 struct Source<T: Send + Sync + 'static>(#[relationship] Entity, PhantomData<T>);
602
603 #[expect(
604 dead_code,
605 reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
606 )]
607 #[derive(Component)]
608 #[relationship_target(relationship=Source<T>)]
609 struct Target<T: Send + Sync + 'static>(#[relationship] Vec<Entity>, PhantomData<T>);
610
611 }
613
614 #[test]
615 fn parent_child_relationship_with_custom_relationship() {
616 #[derive(Component)]
617 #[relationship(relationship_target = RelTarget)]
618 struct Rel(Entity);
619
620 #[derive(Component)]
621 #[relationship_target(relationship = Rel)]
622 struct RelTarget(Entity);
623
624 let mut world = World::new();
625
626 let mut commands = world.commands();
629 let child = commands.spawn_empty().id();
630 let parent = commands.spawn(Rel(child)).add_child(child).id();
631 commands.entity(parent).despawn();
632 world.flush();
633
634 assert!(world.get_entity(child).is_err());
635 assert!(world.get_entity(parent).is_err());
636
637 let mut commands = world.commands();
640 let child = commands.spawn_empty().id();
641 let parent = commands.spawn(Rel(child)).add_child(child).id();
642 commands.entity(child).despawn();
643 world.flush();
644
645 assert!(world.get_entity(child).is_err());
646 assert!(!world.entity(parent).contains::<Rel>());
647
648 let mut commands = world.commands();
651 let parent = commands.spawn_empty().id();
652 let child = commands.spawn((ChildOf(parent), Rel(parent))).id();
653 commands.entity(parent).despawn();
654 world.flush();
655
656 assert!(world.get_entity(child).is_err());
657 assert!(world.get_entity(parent).is_err());
658
659 let mut commands = world.commands();
662 let parent = commands.spawn_empty().id();
663 let child = commands.spawn((ChildOf(parent), Rel(parent))).id();
664 commands.entity(child).despawn();
665 world.flush();
666
667 assert!(world.get_entity(child).is_err());
668 assert!(!world.entity(parent).contains::<RelTarget>());
669 }
670
671 #[test]
672 fn spawn_batch_with_relationship() {
673 let mut world = World::new();
674 let parent = world.spawn_empty().id();
675 let children = world
676 .spawn_batch((0..10).map(|_| ChildOf(parent)))
677 .collect::<Vec<_>>();
678
679 for &child in &children {
680 assert!(world
681 .get::<ChildOf>(child)
682 .is_some_and(|child_of| child_of.parent() == parent));
683 }
684 assert!(world
685 .get::<Children>(parent)
686 .is_some_and(|children| children.len() == 10));
687 }
688
689 #[test]
690 fn insert_batch_with_relationship() {
691 let mut world = World::new();
692 let parent = world.spawn_empty().id();
693 let child = world.spawn_empty().id();
694 world.insert_batch([(child, ChildOf(parent))]);
695 world.flush();
696
697 assert!(world.get::<ChildOf>(child).is_some());
698 assert!(world.get::<Children>(parent).is_some());
699 }
700}