use legion::{
system,
systems::CommandBuffer,
world::{EntityAccessError, SubWorld},
Entity, EntityStore, Query,
};
use crate::core::components::maths::hierarchy::{Children, Parent};
#[system]
pub(crate) fn children_manager(
world: &mut SubWorld,
cmd: &mut CommandBuffer,
query_parent: &mut Query<(Entity, &mut Parent)>,
query_children: &mut Query<(Entity, Option<&mut Children>)>,
) {
let (mut w1, mut w2) = world.split_for_query(query_parent);
query_parent.for_each_mut(&mut w1, |(entity, parent)| {
match query_children.get_mut(&mut w2, parent.0) {
Ok((_, children_component)) => {
if let Some(children_component) = children_component {
if !children_component.0.contains(entity) {
children_component.0.push(*entity);
}
} else {
cmd.add_component(parent.0, Children(vec![*entity]))
}
}
Err(e) => {
match e {
EntityAccessError::AccessDenied => {
cmd.add_component(parent.0, Children(vec![*entity]))
}
EntityAccessError::EntityNotFound => {
cmd.remove(*entity);
}
};
}
}
});
query_children.for_each_mut(&mut w2, |(_e, p)| {
if let Some(p) = p {
let mut to_delete = Vec::new();
for (index, child) in p.0.iter().enumerate() {
if w1.entry_ref(*child).is_err() {
to_delete.push(index);
}
}
to_delete.reverse();
to_delete.iter().for_each(|index| {
p.0.remove(*index);
});
}
});
}
#[cfg(test)]
mod tests {
use legion::{Entity, IntoQuery, Resources, Schedule, World};
use super::*;
use crate::core::components::maths::hierarchy::{Children, Parent};
#[test]
fn children_manager_system_test_children_delete() {
let mut world = World::default();
let mut resources = Resources::default();
let mut schedule = Schedule::builder().add_system(children_manager_system()).build();
let parent = world.push((1,));
let child = world.push((Parent(parent),));
let mut query = <(Entity, &Children)>::query();
assert_eq!(true, query.get(&world, parent).is_err());
schedule.execute(&mut world, &mut resources);
assert_eq!(true, query.get(&mut world, parent).is_ok());
world.remove(parent);
schedule.execute(&mut world, &mut resources);
assert_eq!(true, world.entry(child).is_none());
}
#[test]
fn children_manager_system_test_parent_clean() {
let mut world = World::default();
let mut resources = Resources::default();
let mut schedule = Schedule::builder().add_system(children_manager_system()).build();
let child = world.push((1,));
let parent = world.push((2, Children(vec![child])));
assert_eq!(
true,
world.entry(parent).unwrap().get_component::<Children>().unwrap().0.contains(&child)
);
world.remove(child);
schedule.execute(&mut world, &mut resources);
assert_eq!(0, world.entry(parent).unwrap().get_component::<Children>().unwrap().0.len());
}
}