1use crate::{
2 bundle::Bundle,
3 entity::{hash_set::EntityHashSet, Entity},
4 relationship::{
5 Relationship, RelationshipHookMode, RelationshipSourceCollection, RelationshipTarget,
6 },
7 system::{Commands, EntityCommands},
8 world::{EntityWorldMut, World},
9};
10use bevy_platform::prelude::{Box, Vec};
11use core::{marker::PhantomData, mem};
12
13use super::OrderedRelationshipSourceCollection;
14
15impl<'w> EntityWorldMut<'w> {
16 pub fn with_related<R: Relationship>(&mut self, bundle: impl Bundle) -> &mut Self {
18 let parent = self.id();
19 self.world_scope(|world| {
20 world.spawn((bundle, R::from(parent)));
21 });
22 self
23 }
24
25 pub fn with_related_entities<R: Relationship>(
27 &mut self,
28 func: impl FnOnce(&mut RelatedSpawner<R>),
29 ) -> &mut Self {
30 let parent = self.id();
31 self.world_scope(|world| {
32 func(&mut RelatedSpawner::new(world, parent));
33 });
34 self
35 }
36
37 pub fn add_related<R: Relationship>(&mut self, related: &[Entity]) -> &mut Self {
41 let id = self.id();
42 self.world_scope(|world| {
43 for related in related {
44 world.entity_mut(*related).insert(R::from(id));
45 }
46 });
47 self
48 }
49
50 pub fn insert_related<R: Relationship>(&mut self, index: usize, related: &[Entity]) -> &mut Self
77 where
78 <R::RelationshipTarget as RelationshipTarget>::Collection:
79 OrderedRelationshipSourceCollection,
80 {
81 let id = self.id();
82 self.world_scope(|world| {
83 for (offset, related) in related.iter().enumerate() {
84 let index = index + offset;
85 if world
86 .get::<R>(*related)
87 .is_some_and(|relationship| relationship.get() == id)
88 {
89 world
90 .get_mut::<R::RelationshipTarget>(id)
91 .expect("hooks should have added relationship target")
92 .collection_mut_risky()
93 .place(*related, index);
94 } else {
95 world.entity_mut(*related).insert(R::from(id));
96 world
97 .get_mut::<R::RelationshipTarget>(id)
98 .expect("hooks should have added relationship target")
99 .collection_mut_risky()
100 .place_most_recent(index);
101 }
102 }
103 });
104
105 self
106 }
107
108 pub fn remove_related<R: Relationship>(&mut self, related: &[Entity]) -> &mut Self {
110 let id = self.id();
111 self.world_scope(|world| {
112 for related in related {
113 if world
114 .get::<R>(*related)
115 .is_some_and(|relationship| relationship.get() == id)
116 {
117 world.entity_mut(*related).remove::<R>();
118 }
119 }
120 });
121
122 self
123 }
124
125 pub fn replace_related<R: Relationship>(&mut self, related: &[Entity]) -> &mut Self {
127 type Collection<R> =
128 <<R as Relationship>::RelationshipTarget as RelationshipTarget>::Collection;
129
130 if related.is_empty() {
131 self.remove::<R::RelationshipTarget>();
132
133 return self;
134 }
135
136 let Some(mut existing_relations) = self.get_mut::<R::RelationshipTarget>() else {
137 return self.add_related::<R>(related);
138 };
139
140 let mut existing_relations = mem::replace(
143 existing_relations.collection_mut_risky(),
144 Collection::<R>::with_capacity(0),
145 );
146
147 let mut potential_relations = EntityHashSet::from_iter(related.iter().copied());
148
149 let id = self.id();
150 self.world_scope(|world| {
151 for related in existing_relations.iter() {
152 if !potential_relations.remove(related) {
153 world.entity_mut(related).remove::<R>();
154 }
155 }
156
157 for related in potential_relations {
158 world
160 .entity_mut(related)
161 .insert_with_relationship_hook_mode(R::from(id), RelationshipHookMode::Skip);
162 }
163 });
164
165 existing_relations.clear();
167 existing_relations.extend_from_iter(related.iter().copied());
168 self.insert(R::RelationshipTarget::from_collection_risky(
169 existing_relations,
170 ));
171
172 self
173 }
174
175 pub fn replace_related_with_difference<R: Relationship>(
196 &mut self,
197 entities_to_unrelate: &[Entity],
198 entities_to_relate: &[Entity],
199 newly_related_entities: &[Entity],
200 ) -> &mut Self {
201 #[cfg(debug_assertions)]
202 {
203 let entities_to_relate = EntityHashSet::from_iter(entities_to_relate.iter().copied());
204 let entities_to_unrelate =
205 EntityHashSet::from_iter(entities_to_unrelate.iter().copied());
206 let mut newly_related_entities =
207 EntityHashSet::from_iter(newly_related_entities.iter().copied());
208 assert!(
209 entities_to_relate.is_disjoint(&entities_to_unrelate),
210 "`entities_to_relate` ({entities_to_relate:?}) shared entities with `entities_to_unrelate` ({entities_to_unrelate:?})"
211 );
212 assert!(
213 newly_related_entities.is_disjoint(&entities_to_unrelate),
214 "`newly_related_entities` ({newly_related_entities:?}) shared entities with `entities_to_unrelate ({entities_to_unrelate:?})`"
215 );
216 assert!(
217 newly_related_entities.is_subset(&entities_to_relate),
218 "`newly_related_entities` ({newly_related_entities:?}) wasn't a subset of `entities_to_relate` ({entities_to_relate:?})"
219 );
220
221 if let Some(target) = self.get::<R::RelationshipTarget>() {
222 let existing_relationships: EntityHashSet = target.collection().iter().collect();
223
224 assert!(
225 existing_relationships.is_disjoint(&newly_related_entities),
226 "`newly_related_entities` contains an entity that wouldn't be newly related"
227 );
228
229 newly_related_entities.extend(existing_relationships);
230 newly_related_entities -= &entities_to_unrelate;
231 }
232
233 assert_eq!(newly_related_entities, entities_to_relate, "`entities_to_relate` ({entities_to_relate:?}) didn't contain all entities that would end up related");
234 };
235
236 if !self.contains::<R::RelationshipTarget>() {
237 self.add_related::<R>(entities_to_relate);
238
239 return self;
240 };
241
242 let this = self.id();
243 self.world_scope(|world| {
244 for unrelate in entities_to_unrelate {
245 world.entity_mut(*unrelate).remove::<R>();
246 }
247
248 for new_relation in newly_related_entities {
249 world
251 .entity_mut(*new_relation)
252 .insert_with_relationship_hook_mode(R::from(this), RelationshipHookMode::Skip);
253 }
254 });
255
256 if !entities_to_relate.is_empty() {
257 if let Some(mut target) = self.get_mut::<R::RelationshipTarget>() {
258 let collection = target.collection_mut_risky();
260 collection.clear();
261
262 collection.extend_from_iter(entities_to_relate.iter().copied());
263 } else {
264 let mut empty =
265 <R::RelationshipTarget as RelationshipTarget>::Collection::with_capacity(
266 entities_to_relate.len(),
267 );
268 empty.extend_from_iter(entities_to_relate.iter().copied());
269
270 self.insert(R::RelationshipTarget::from_collection_risky(empty));
272 }
273 }
274
275 self
276 }
277
278 pub fn add_one_related<R: Relationship>(&mut self, entity: Entity) -> &mut Self {
282 self.add_related::<R>(&[entity])
283 }
284
285 pub fn despawn_related<S: RelationshipTarget>(&mut self) -> &mut Self {
288 if let Some(sources) = self.take::<S>() {
289 self.world_scope(|world| {
290 for entity in sources.iter() {
291 if let Ok(entity_mut) = world.get_entity_mut(entity) {
292 entity_mut.despawn();
293 }
294 }
295 });
296 }
297 self
298 }
299
300 pub fn insert_recursive<S: RelationshipTarget>(
310 &mut self,
311 bundle: impl Bundle + Clone,
312 ) -> &mut Self {
313 self.insert(bundle.clone());
314 if let Some(relationship_target) = self.get::<S>() {
315 let related_vec: Vec<Entity> = relationship_target.iter().collect();
316 for related in related_vec {
317 self.world_scope(|world| {
318 world
319 .entity_mut(related)
320 .insert_recursive::<S>(bundle.clone());
321 });
322 }
323 }
324
325 self
326 }
327
328 pub fn remove_recursive<S: RelationshipTarget, B: Bundle>(&mut self) -> &mut Self {
336 self.remove::<B>();
337 if let Some(relationship_target) = self.get::<S>() {
338 let related_vec: Vec<Entity> = relationship_target.iter().collect();
339 for related in related_vec {
340 self.world_scope(|world| {
341 world.entity_mut(related).remove_recursive::<S, B>();
342 });
343 }
344 }
345
346 self
347 }
348}
349
350impl<'a> EntityCommands<'a> {
351 pub fn with_related<R: Relationship>(&mut self, bundle: impl Bundle) -> &mut Self {
353 let parent = self.id();
354 self.commands.spawn((bundle, R::from(parent)));
355 self
356 }
357
358 pub fn with_related_entities<R: Relationship>(
360 &mut self,
361 func: impl FnOnce(&mut RelatedSpawnerCommands<R>),
362 ) -> &mut Self {
363 let id = self.id();
364 func(&mut RelatedSpawnerCommands::new(self.commands(), id));
365 self
366 }
367
368 pub fn add_related<R: Relationship>(&mut self, related: &[Entity]) -> &mut Self {
372 let related: Box<[Entity]> = related.into();
373
374 self.queue(move |mut entity: EntityWorldMut| {
375 entity.add_related::<R>(&related);
376 })
377 }
378
379 pub fn insert_related<R: Relationship>(&mut self, index: usize, related: &[Entity]) -> &mut Self
385 where
386 <R::RelationshipTarget as RelationshipTarget>::Collection:
387 OrderedRelationshipSourceCollection,
388 {
389 let related: Box<[Entity]> = related.into();
390
391 self.queue(move |mut entity: EntityWorldMut| {
392 entity.insert_related::<R>(index, &related);
393 })
394 }
395
396 pub fn add_one_related<R: Relationship>(&mut self, entity: Entity) -> &mut Self {
400 self.add_related::<R>(&[entity])
401 }
402
403 pub fn remove_related<R: Relationship>(&mut self, related: &[Entity]) -> &mut Self {
405 let related: Box<[Entity]> = related.into();
406
407 self.queue(move |mut entity: EntityWorldMut| {
408 entity.remove_related::<R>(&related);
409 })
410 }
411
412 pub fn replace_related<R: Relationship>(&mut self, related: &[Entity]) -> &mut Self {
414 let related: Box<[Entity]> = related.into();
415
416 self.queue(move |mut entity: EntityWorldMut| {
417 entity.replace_related::<R>(&related);
418 })
419 }
420
421 pub fn replace_related_with_difference<R: Relationship>(
432 &mut self,
433 entities_to_unrelate: &[Entity],
434 entities_to_relate: &[Entity],
435 newly_related_entities: &[Entity],
436 ) -> &mut Self {
437 let entities_to_unrelate: Box<[Entity]> = entities_to_unrelate.into();
438 let entities_to_relate: Box<[Entity]> = entities_to_relate.into();
439 let newly_related_entities: Box<[Entity]> = newly_related_entities.into();
440
441 self.queue(move |mut entity: EntityWorldMut| {
442 entity.replace_related_with_difference::<R>(
443 &entities_to_unrelate,
444 &entities_to_relate,
445 &newly_related_entities,
446 );
447 })
448 }
449
450 pub fn despawn_related<S: RelationshipTarget>(&mut self) -> &mut Self {
453 self.queue(move |mut entity: EntityWorldMut| {
454 entity.despawn_related::<S>();
455 })
456 }
457
458 pub fn insert_recursive<S: RelationshipTarget>(
466 &mut self,
467 bundle: impl Bundle + Clone,
468 ) -> &mut Self {
469 self.queue(move |mut entity: EntityWorldMut| {
470 entity.insert_recursive::<S>(bundle);
471 })
472 }
473
474 pub fn remove_recursive<S: RelationshipTarget, B: Bundle>(&mut self) -> &mut Self {
482 self.queue(move |mut entity: EntityWorldMut| {
483 entity.remove_recursive::<S, B>();
484 })
485 }
486}
487
488pub struct RelatedSpawner<'w, R: Relationship> {
491 target: Entity,
492 world: &'w mut World,
493 _marker: PhantomData<R>,
494}
495
496impl<'w, R: Relationship> RelatedSpawner<'w, R> {
497 pub fn new(world: &'w mut World, target: Entity) -> Self {
499 Self {
500 world,
501 target,
502 _marker: PhantomData,
503 }
504 }
505
506 pub fn spawn(&mut self, bundle: impl Bundle) -> EntityWorldMut<'_> {
509 self.world.spawn((R::from(self.target), bundle))
510 }
511
512 pub fn spawn_empty(&mut self) -> EntityWorldMut<'_> {
515 self.world.spawn(R::from(self.target))
516 }
517
518 pub fn target_entity(&self) -> Entity {
520 self.target
521 }
522}
523
524pub struct RelatedSpawnerCommands<'w, R: Relationship> {
527 target: Entity,
528 commands: Commands<'w, 'w>,
529 _marker: PhantomData<R>,
530}
531
532impl<'w, R: Relationship> RelatedSpawnerCommands<'w, R> {
533 pub fn new(commands: Commands<'w, 'w>, target: Entity) -> Self {
535 Self {
536 commands,
537 target,
538 _marker: PhantomData,
539 }
540 }
541
542 pub fn spawn(&mut self, bundle: impl Bundle) -> EntityCommands<'_> {
545 self.commands.spawn((R::from(self.target), bundle))
546 }
547
548 pub fn spawn_empty(&mut self) -> EntityCommands<'_> {
551 self.commands.spawn(R::from(self.target))
552 }
553
554 pub fn target_entity(&self) -> Entity {
556 self.target
557 }
558
559 pub fn commands(&mut self) -> Commands {
561 self.commands.reborrow()
562 }
563
564 pub fn commands_mut(&mut self) -> &mut Commands<'w, 'w> {
566 &mut self.commands
567 }
568}
569
570#[cfg(test)]
571mod tests {
572 use super::*;
573 use crate::prelude::{ChildOf, Children, Component};
574
575 #[derive(Component, Clone, Copy)]
576 struct TestComponent;
577
578 #[test]
579 fn insert_and_remove_recursive() {
580 let mut world = World::new();
581
582 let a = world.spawn_empty().id();
583 let b = world.spawn(ChildOf(a)).id();
584 let c = world.spawn(ChildOf(a)).id();
585 let d = world.spawn(ChildOf(b)).id();
586
587 world
588 .entity_mut(a)
589 .insert_recursive::<Children>(TestComponent);
590
591 for entity in [a, b, c, d] {
592 assert!(world.entity(entity).contains::<TestComponent>());
593 }
594
595 world
596 .entity_mut(b)
597 .remove_recursive::<Children, TestComponent>();
598
599 assert!(world.entity(a).contains::<TestComponent>());
601 assert!(!world.entity(b).contains::<TestComponent>());
603 assert!(world.entity(c).contains::<TestComponent>());
605 assert!(!world.entity(d).contains::<TestComponent>());
607
608 world
609 .entity_mut(a)
610 .remove_recursive::<Children, TestComponent>();
611
612 for entity in [a, b, c, d] {
613 assert!(!world.entity(entity).contains::<TestComponent>());
614 }
615 }
616}