212 lines
8.0 KiB
Rust
212 lines
8.0 KiB
Rust
#![allow(dead_code)]
|
|
use crate::{components::*, ecs::prelude::*};
|
|
use smallvec::SmallVec;
|
|
use std::collections::HashMap;
|
|
|
|
pub fn build(_: &mut World) -> Vec<Box<dyn Schedulable>> {
|
|
let missing_previous_parent_system = SystemBuilder::<()>::new("MissingPreviousParentSystem")
|
|
// Entities with missing `PreviousParent`
|
|
.with_query(<Read<Parent>>::query().filter(!component::<PreviousParent>()))
|
|
.build(move |commands, world, _resource, query| {
|
|
// Add missing `PreviousParent` components
|
|
for (entity, _parent) in query.iter_entities(world) {
|
|
log::trace!("Adding missing PreviousParent to {}", entity);
|
|
commands.add_component(entity, PreviousParent(None));
|
|
}
|
|
});
|
|
|
|
let parent_update_system = SystemBuilder::<()>::new("ParentUpdateSystem")
|
|
// Entities with a removed `Parent`
|
|
.with_query(<Read<PreviousParent>>::query().filter(!component::<Parent>()))
|
|
// Entities with a changed `Parent`
|
|
.with_query(<(Read<Parent>, Write<PreviousParent>)>::query().filter(changed::<Parent>()))
|
|
// Deleted Parents (ie Entities with `Children` and without a `LocalToWorld`).
|
|
.write_component::<Children>()
|
|
.build(move |commands, world, _resource, queries| {
|
|
// Entities with a missing `Parent` (ie. ones that have a `PreviousParent`), remove
|
|
// them from the `Children` of the `PreviousParent`.
|
|
for (entity, previous_parent) in queries.0.iter_entities(world) {
|
|
log::trace!("Parent was removed from {}", entity);
|
|
if let Some(previous_parent_entity) = previous_parent.0 {
|
|
if let Some(mut previous_parent_children) =
|
|
world.get_component_mut::<Children>(previous_parent_entity)
|
|
{
|
|
log::trace!(" > Removing {} from it's prev parent's children", entity);
|
|
previous_parent_children.0.retain(|e| *e != entity);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Tracks all newly created `Children` Components this frame.
|
|
let mut children_additions =
|
|
HashMap::<Entity, SmallVec<[Entity; 8]>>::with_capacity(16);
|
|
|
|
// Entities with a changed Parent (that also have a PreviousParent, even if None)
|
|
for (entity, (parent, mut previous_parent)) in queries.1.iter_entities_mut(world) {
|
|
log::trace!("Parent changed for {}", entity);
|
|
|
|
// If the `PreviousParent` is not None.
|
|
if let Some(previous_parent_entity) = previous_parent.0 {
|
|
// New and previous point to the same Entity, carry on, nothing to see here.
|
|
if previous_parent_entity == parent.0 {
|
|
log::trace!(" > But the previous parent is the same, ignoring...");
|
|
continue;
|
|
}
|
|
|
|
// Remove from `PreviousParent.Children`.
|
|
if let Some(mut previous_parent_children) =
|
|
world.get_component_mut::<Children>(previous_parent_entity)
|
|
{
|
|
log::trace!(" > Removing {} from prev parent's children", entity);
|
|
(*previous_parent_children).0.retain(|e| *e != entity);
|
|
}
|
|
}
|
|
|
|
// Set `PreviousParent = Parent`.
|
|
*previous_parent = PreviousParent(Some(parent.0));
|
|
|
|
// Add to the parent's `Children` (either the real component, or
|
|
// `children_additions`).
|
|
log::trace!("Adding {} to it's new parent {}", entity, parent.0);
|
|
if let Some(mut new_parent_children) = world.get_component_mut::<Children>(parent.0)
|
|
{
|
|
// This is the parent
|
|
log::trace!(
|
|
" > The new parent {} already has a `Children`, adding to it.",
|
|
parent.0
|
|
);
|
|
(*new_parent_children).0.push(entity);
|
|
} else {
|
|
// The parent doesn't have a children entity, lets add it
|
|
log::trace!(
|
|
"The new parent {} doesn't yet have `Children` component.",
|
|
parent.0
|
|
);
|
|
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(|(k, v)| {
|
|
log::trace!("Flushing: Entity {} adding `Children` component {:?}", k, v);
|
|
commands.add_component(*k, Children::with(v));
|
|
});
|
|
});
|
|
|
|
vec![missing_previous_parent_system, parent_update_system]
|
|
}
|
|
|
|
// #[cfg(test)]
|
|
// mod test {
|
|
// use super::*;
|
|
|
|
// #[test]
|
|
// fn correct_children() {
|
|
// let _ = env_logger::builder().is_test(true).try_init();
|
|
|
|
// let mut world = Universe::new().create_world();
|
|
|
|
// let systems = build(&mut world);
|
|
|
|
// // Add parent entities
|
|
// let parent = *world
|
|
// .insert(
|
|
// (),
|
|
// vec![(Translation::identity(), LocalToWorld::identity())],
|
|
// )
|
|
// .first()
|
|
// .unwrap();
|
|
// let children = world.insert(
|
|
// (),
|
|
// vec![
|
|
// (
|
|
// Translation::identity(),
|
|
// LocalToParent::identity(),
|
|
// LocalToWorld::identity(),
|
|
// ),
|
|
// (
|
|
// Translation::identity(),
|
|
// LocalToParent::identity(),
|
|
// LocalToWorld::identity(),
|
|
// ),
|
|
// ],
|
|
// );
|
|
// let (e1, e2) = (children[0], children[1]);
|
|
|
|
// // Parent `e1` and `e2` to `parent`.
|
|
// world.add_component(e1, Parent(parent));
|
|
// world.add_component(e2, Parent(parent));
|
|
|
|
// for system in systems.iter() {
|
|
// system.run(&mut world);
|
|
// system.command_buffer_mut().write(&mut world);
|
|
// }
|
|
|
|
// assert_eq!(
|
|
// world
|
|
// .get_component::<Children>(parent)
|
|
// .unwrap()
|
|
// .0
|
|
// .iter()
|
|
// .cloned()
|
|
// .collect::<Vec<_>>(),
|
|
// vec![e1, e2]
|
|
// );
|
|
|
|
// // Parent `e1` to `e2`.
|
|
// (*world.get_component_mut::<Parent>(e1).unwrap()).0 = e2;
|
|
|
|
// // Run the system on it
|
|
// for system in systems.iter() {
|
|
// system.run(&mut world);
|
|
// system.command_buffer_mut().write(&mut world);
|
|
// }
|
|
|
|
// assert_eq!(
|
|
// world
|
|
// .get_component::<Children>(parent)
|
|
// .unwrap()
|
|
// .0
|
|
// .iter()
|
|
// .cloned()
|
|
// .collect::<Vec<_>>(),
|
|
// vec![e2]
|
|
// );
|
|
|
|
// assert_eq!(
|
|
// world
|
|
// .get_component::<Children>(e2)
|
|
// .unwrap()
|
|
// .0
|
|
// .iter()
|
|
// .cloned()
|
|
// .collect::<Vec<_>>(),
|
|
// vec![e1]
|
|
// );
|
|
|
|
// world.delete(e1);
|
|
|
|
// // Run the system on it
|
|
// for system in systems.iter() {
|
|
// system.run(&mut world);
|
|
// system.command_buffer_mut().write(&mut world);
|
|
// }
|
|
|
|
// assert_eq!(
|
|
// world
|
|
// .get_component::<Children>(parent)
|
|
// .unwrap()
|
|
// .0
|
|
// .iter()
|
|
// .cloned()
|
|
// .collect::<Vec<_>>(),
|
|
// vec![e2]
|
|
// );
|
|
// }
|
|
// }
|