@@ -12,7 +12,7 @@ use crate::{
1212 bundle:: Bundle ,
1313 component:: { Component , HookContext } ,
1414 entity:: Entity ,
15- relationship:: { RelatedSpawner , RelatedSpawnerCommands } ,
15+ relationship:: { RelatedSpawner , RelatedSpawnerCommands , Relationship } ,
1616 system:: EntityCommands ,
1717 world:: { DeferredWorld , EntityWorldMut , FromWorld , World } ,
1818} ;
@@ -179,11 +179,33 @@ impl<'w> EntityWorldMut<'w> {
179179 self . add_related :: < ChildOf > ( & [ child] )
180180 }
181181
182- /// Replaces the children on this entity with a new list of children.
182+ /// Replaces all the related children with a new set of children.
183183 pub fn replace_children ( & mut self , children : & [ Entity ] ) -> & mut Self {
184184 self . replace_related :: < ChildOf > ( children)
185185 }
186186
187+ /// Replaces all the related children with a new set of children.
188+ ///
189+ /// # Warning
190+ /// Not maintaining the function invariants may lead to erratic engine behavior including random crashes.
191+ /// See [`Self::replace_related_with_difference`] for invariants.
192+ ///
193+ /// # Panics
194+ ///
195+ /// In debug mode when function invariants are broken.
196+ pub fn replace_children_with_difference (
197+ & mut self ,
198+ entities_to_unrelate : & [ Entity ] ,
199+ entities_to_relate : & [ Entity ] ,
200+ newly_related_entities : & [ Entity ] ,
201+ ) -> & mut Self {
202+ self . replace_related_with_difference :: < ChildOf > (
203+ entities_to_unrelate,
204+ entities_to_relate,
205+ newly_related_entities,
206+ )
207+ }
208+
187209 /// Spawns the passed bundle and adds it to this entity as a child.
188210 ///
189211 /// For efficient spawning of multiple children, use [`with_children`].
@@ -240,6 +262,28 @@ impl<'a> EntityCommands<'a> {
240262 self . replace_related :: < ChildOf > ( children)
241263 }
242264
265+ /// Replaces all the related entities with a new set of entities.
266+ ///
267+ /// # Warning
268+ /// Not maintaining the function invariants may lead to erratic engine behavior including random crashes.
269+ /// See [`EntityWorldMut::replace_related_with_difference`] for invariants.
270+ ///
271+ /// # Panics
272+ ///
273+ /// In debug mode when function invariants are broken.
274+ pub fn replace_children_with_difference < R : Relationship > (
275+ & mut self ,
276+ entities_to_unrelate : & [ Entity ] ,
277+ entities_to_relate : & [ Entity ] ,
278+ newly_related_entities : & [ Entity ] ,
279+ ) -> & mut Self {
280+ self . replace_related_with_difference :: < R > (
281+ entities_to_unrelate,
282+ entities_to_relate,
283+ newly_related_entities,
284+ )
285+ }
286+
243287 /// Spawns the passed bundle and adds it to this entity as a child.
244288 ///
245289 /// For efficient spawning of multiple children, use [`with_children`].
@@ -336,6 +380,8 @@ macro_rules! children {
336380
337381#[ cfg( test) ]
338382mod tests {
383+ use core:: ops:: { Deref , DerefMut } ;
384+
339385 use crate :: {
340386 entity:: Entity ,
341387 hierarchy:: { ChildOf , Children } ,
@@ -533,4 +579,169 @@ mod tests {
533579
534580 assert ! ( world. entity( parent) . get:: <Children >( ) . is_none( ) ) ;
535581 }
582+
583+ #[ test]
584+ fn insert_same_child_twice ( ) {
585+ let mut world = World :: new ( ) ;
586+
587+ let parent = world. spawn_empty ( ) . id ( ) ;
588+ let child = world. spawn_empty ( ) . id ( ) ;
589+
590+ world. entity_mut ( parent) . add_child ( child) ;
591+ world. entity_mut ( parent) . add_child ( child) ;
592+
593+ let children = world. get :: < Children > ( parent) . unwrap ( ) ;
594+ assert_eq ! ( children. 0 , [ child] ) ;
595+ }
596+
597+ #[ test]
598+ fn replace_with_difference ( ) {
599+ let mut world = World :: new ( ) ;
600+
601+ let parent = world. spawn_empty ( ) . id ( ) ;
602+ let child_a = world. spawn_empty ( ) . id ( ) ;
603+ let child_b = world. spawn_empty ( ) . id ( ) ;
604+ let child_c = world. spawn_empty ( ) . id ( ) ;
605+ let child_d = world. spawn_empty ( ) . id ( ) ;
606+
607+ // Test inserting new relations
608+ world. entity_mut ( parent) . replace_children_with_difference (
609+ & [ ] ,
610+ & [ child_a, child_b] ,
611+ & [ child_a, child_b] ,
612+ ) ;
613+
614+ assert_eq ! (
615+ world. entity( child_a) . get:: <ChildOf >( ) . unwrap( ) ,
616+ & ChildOf { parent }
617+ ) ;
618+ assert_eq ! (
619+ world. entity( child_b) . get:: <ChildOf >( ) . unwrap( ) ,
620+ & ChildOf { parent }
621+ ) ;
622+ assert_eq ! (
623+ world. entity( parent) . get:: <Children >( ) . unwrap( ) . 0 ,
624+ [ child_a, child_b]
625+ ) ;
626+
627+ // Test replacing relations and changing order
628+ world. entity_mut ( parent) . replace_children_with_difference (
629+ & [ child_b] ,
630+ & [ child_d, child_c, child_a] ,
631+ & [ child_c, child_d] ,
632+ ) ;
633+ assert_eq ! (
634+ world. entity( child_a) . get:: <ChildOf >( ) . unwrap( ) ,
635+ & ChildOf { parent }
636+ ) ;
637+ assert_eq ! (
638+ world. entity( child_c) . get:: <ChildOf >( ) . unwrap( ) ,
639+ & ChildOf { parent }
640+ ) ;
641+ assert_eq ! (
642+ world. entity( child_d) . get:: <ChildOf >( ) . unwrap( ) ,
643+ & ChildOf { parent }
644+ ) ;
645+ assert_eq ! (
646+ world. entity( parent) . get:: <Children >( ) . unwrap( ) . 0 ,
647+ [ child_d, child_c, child_a]
648+ ) ;
649+ assert ! ( !world. entity( child_b) . contains:: <ChildOf >( ) ) ;
650+
651+ // Test removing relationships
652+ world. entity_mut ( parent) . replace_children_with_difference (
653+ & [ child_a, child_d, child_c] ,
654+ & [ ] ,
655+ & [ ] ,
656+ ) ;
657+ assert ! ( !world. entity( parent) . contains:: <Children >( ) ) ;
658+ assert ! ( !world. entity( child_a) . contains:: <ChildOf >( ) ) ;
659+ assert ! ( !world. entity( child_b) . contains:: <ChildOf >( ) ) ;
660+ assert ! ( !world. entity( child_c) . contains:: <ChildOf >( ) ) ;
661+ assert ! ( !world. entity( child_d) . contains:: <ChildOf >( ) ) ;
662+ }
663+
664+ #[ test]
665+ fn replace_with_difference_on_empty ( ) {
666+ let mut world = World :: new ( ) ;
667+
668+ let parent = world. spawn_empty ( ) . id ( ) ;
669+ let child_a = world. spawn_empty ( ) . id ( ) ;
670+
671+ world
672+ . entity_mut ( parent)
673+ . replace_children_with_difference ( & [ child_a] , & [ ] , & [ ] ) ;
674+
675+ assert ! ( !world. entity( parent) . contains:: <Children >( ) ) ;
676+ assert ! ( !world. entity( child_a) . contains:: <ChildOf >( ) ) ;
677+ }
678+
679+ #[ test]
680+ #[ should_panic]
681+ #[ cfg_attr(
682+ not( debug_assertions) ,
683+ ignore = "we don't check invariants if debug assertions are off"
684+ ) ]
685+ fn replace_diff_invariant_overlapping_unrelate_with_relate ( ) {
686+ let mut world = World :: new ( ) ;
687+
688+ let parent = world. spawn_empty ( ) . id ( ) ;
689+ let child_a = world. spawn_empty ( ) . id ( ) ;
690+
691+ world
692+ . entity_mut ( parent)
693+ . replace_children_with_difference ( & [ ] , & [ child_a] , & [ child_a] ) ;
694+
695+ // This should panic
696+ world
697+ . entity_mut ( parent)
698+ . replace_children_with_difference ( & [ child_a] , & [ child_a] , & [ ] ) ;
699+ }
700+
701+ #[ test]
702+ #[ should_panic]
703+ #[ cfg_attr(
704+ not( debug_assertions) ,
705+ ignore = "we don't check invariants if debug assertions are off"
706+ ) ]
707+
708+ fn replace_diff_invariant_overlapping_unrelate_with_newly ( ) {
709+ let mut world = World :: new ( ) ;
710+
711+ let parent = world. spawn_empty ( ) . id ( ) ;
712+ let child_a = world. spawn_empty ( ) . id ( ) ;
713+ let child_b = world. spawn_empty ( ) . id ( ) ;
714+
715+ world
716+ . entity_mut ( parent)
717+ . replace_children_with_difference ( & [ ] , & [ child_a] , & [ child_a] ) ;
718+
719+ // This should panic
720+ world. entity_mut ( parent) . replace_children_with_difference (
721+ & [ child_b] ,
722+ & [ child_a, child_b] ,
723+ & [ child_b] ,
724+ ) ;
725+ }
726+
727+ #[ test]
728+ #[ should_panic]
729+ #[ cfg_attr(
730+ not( debug_assertions) ,
731+ ignore = "we don't check invariants if debug assertions are off"
732+ ) ]
733+ fn replace_diff_invariant_newly_not_subset ( ) {
734+ let mut world = World :: new ( ) ;
735+
736+ let parent = world. spawn_empty ( ) . id ( ) ;
737+ let child_a = world. spawn_empty ( ) . id ( ) ;
738+ let child_b = world. spawn_empty ( ) . id ( ) ;
739+
740+ // This should panic
741+ world. entity_mut ( parent) . replace_children_with_difference (
742+ & [ ] ,
743+ & [ child_a, child_b] ,
744+ & [ child_a] ,
745+ ) ;
746+ }
536747}
0 commit comments