-
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
/
Copy pathsystems.rs
72 lines (65 loc) · 2.92 KB
/
systems.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
use crate::components::*;
use bevy_ecs::{
entity::Entity,
prelude::Changed,
query::Without,
system::{Commands, Query},
};
use bevy_utils::HashMap;
use smallvec::SmallVec;
/// Updates parents when the hierarchy is changed
pub fn parent_update_system(
mut commands: Commands,
removed_parent_query: Query<(Entity, &PreviousParent), Without<Parent>>,
mut parent_query: Query<(Entity, &Parent, Option<&mut PreviousParent>), Changed<Parent>>,
mut children_query: Query<&mut Children>,
) {
// Entities with a missing `Parent` (ie. ones that have a `PreviousParent`), remove
// them from the `Children` of the `PreviousParent`.
for (entity, previous_parent) in removed_parent_query.iter() {
if let Ok(mut previous_parent_children) = children_query.get_mut(previous_parent.0) {
previous_parent_children.0.retain(|e| *e != entity);
commands.entity(entity).remove::<PreviousParent>();
}
}
// Tracks all newly created `Children` Components this frame.
let mut children_additions = HashMap::<Entity, SmallVec<[Entity; 8]>>::default();
// Entities with a changed Parent (that also have a PreviousParent, even if None)
for (entity, parent, possible_previous_parent) in parent_query.iter_mut() {
if let Some(mut previous_parent) = possible_previous_parent {
// New and previous point to the same Entity, carry on, nothing to see here.
if previous_parent.0 == parent.0 {
continue;
}
// Remove from `PreviousParent.Children`.
if let Ok(mut previous_parent_children) = children_query.get_mut(previous_parent.0) {
(*previous_parent_children).0.retain(|e| *e != entity);
}
// Set `PreviousParent = Parent`.
*previous_parent = PreviousParent(parent.0);
} else {
commands.entity(entity).insert(PreviousParent(parent.0));
};
// Add to the parent's `Children` (either the real component, or
// `children_additions`).
if let Ok(mut new_parent_children) = children_query.get_mut(parent.0) {
// This is the parent
// PERF: Ideally we shouldn't need to check for duplicates
if !(*new_parent_children).0.contains(&entity) {
(*new_parent_children).0.push(entity);
}
} else {
// The parent doesn't have a children entity, lets add it
children_additions
.entry(parent.0)
.or_insert_with(Default::default)
.push(entity);
}
}
// Flush the `children_additions` to the command buffer. It is stored separate to
// collect multiple new children that point to the same parent into the same
// SmallVec, and to prevent redundant add+remove operations.
children_additions.iter().for_each(|(e, v)| {
commands.entity(*e).insert(Children::with(v));
});
}