@@ -11,16 +11,21 @@ pub fn transform_propagate_system(
11
11
& Transform ,
12
12
Changed < Transform > ,
13
13
& mut GlobalTransform ,
14
+ Entity ,
14
15
) ,
15
16
Without < Parent > ,
16
17
> ,
17
- mut transform_query : Query <
18
- ( & Transform , Changed < Transform > , & mut GlobalTransform ) ,
19
- With < Parent > ,
20
- > ,
18
+ mut transform_query : Query < (
19
+ & Transform ,
20
+ Changed < Transform > ,
21
+ & mut GlobalTransform ,
22
+ & Parent ,
23
+ ) > ,
21
24
children_query : Query < ( & Children , Changed < Children > ) , ( With < Parent > , With < GlobalTransform > ) > ,
22
25
) {
23
- for ( children, transform, transform_changed, mut global_transform) in root_query. iter_mut ( ) {
26
+ for ( children, transform, transform_changed, mut global_transform, entity) in
27
+ root_query. iter_mut ( )
28
+ {
24
29
let mut changed = transform_changed;
25
30
if transform_changed {
26
31
* global_transform = GlobalTransform :: from ( * transform) ;
@@ -35,6 +40,7 @@ pub fn transform_propagate_system(
35
40
& mut transform_query,
36
41
& children_query,
37
42
* child,
43
+ entity,
38
44
changed,
39
45
) ;
40
46
}
@@ -44,19 +50,26 @@ pub fn transform_propagate_system(
44
50
45
51
fn propagate_recursive (
46
52
parent : & GlobalTransform ,
47
- transform_query : & mut Query <
48
- ( & Transform , Changed < Transform > , & mut GlobalTransform ) ,
49
- With < Parent > ,
50
- > ,
53
+ transform_query : & mut Query < (
54
+ & Transform ,
55
+ Changed < Transform > ,
56
+ & mut GlobalTransform ,
57
+ & Parent ,
58
+ ) > ,
51
59
children_query : & Query < ( & Children , Changed < Children > ) , ( With < Parent > , With < GlobalTransform > ) > ,
52
60
entity : Entity ,
61
+ expected_parent : Entity ,
53
62
mut changed : bool ,
54
63
// We use a result here to use the `?` operator. Ideally we'd use a try block instead
55
64
) -> Result < ( ) , ( ) > {
56
65
let global_matrix = {
57
- let ( transform, transform_changed, mut global_transform) =
66
+ let ( transform, transform_changed, mut global_transform, child_parent ) =
58
67
transform_query. get_mut ( entity) . map_err ( drop) ?;
59
-
68
+ // Note that for parallelising, this check cannot occur here, since there is an `&mut GlobalTransform` (in global_transform)
69
+ assert_eq ! (
70
+ child_parent. 0 , expected_parent,
71
+ "Malformed hierarchy. This probably means that your hierarchy has been improperly maintained, or contains a cycle"
72
+ ) ;
60
73
changed |= transform_changed;
61
74
if changed {
62
75
* global_transform = parent. mul_transform ( * transform) ;
@@ -73,6 +86,7 @@ fn propagate_recursive(
73
86
transform_query,
74
87
children_query,
75
88
* child,
89
+ entity,
76
90
changed,
77
91
) ;
78
92
}
@@ -322,4 +336,36 @@ mod test {
322
336
) ;
323
337
}
324
338
}
339
+ #[ test]
340
+ #[ should_panic]
341
+ fn panic_when_hierarchy_cycle ( ) {
342
+ let mut app = App :: new ( ) ;
343
+
344
+ app. add_system ( parent_update_system) ;
345
+ app. add_system ( transform_propagate_system) ;
346
+
347
+ let child = app
348
+ . world
349
+ . spawn ( )
350
+ . insert_bundle ( ( Transform :: identity ( ) , GlobalTransform :: default ( ) ) )
351
+ . id ( ) ;
352
+
353
+ let grandchild = app
354
+ . world
355
+ . spawn ( )
356
+ . insert_bundle ( (
357
+ Transform :: identity ( ) ,
358
+ GlobalTransform :: default ( ) ,
359
+ Parent ( child) ,
360
+ ) )
361
+ . id ( ) ;
362
+ app. world . spawn ( ) . insert_bundle ( (
363
+ Transform :: default ( ) ,
364
+ GlobalTransform :: default ( ) ,
365
+ Children :: with ( & [ child] ) ,
366
+ ) ) ;
367
+ app. world . entity_mut ( child) . insert ( Parent ( grandchild) ) ;
368
+
369
+ app. update ( ) ;
370
+ }
325
371
}
0 commit comments