use bevy::ecs::component::Mutable;
use bevy::prelude::*;
pub fn get_ancestor_mut<T: Component<Mutability = Mutable>>(
world: &mut World,
entity: Entity,
) -> Option<(Entity, &mut T)>
{
get_ancestor_mut_filtered(world, entity, |_| true)
}
pub fn get_ancestor_mut_filtered<T: Component<Mutability = Mutable>>(
world: &mut World,
entity: Entity,
filter: impl Fn(&T) -> bool,
) -> Option<(Entity, &mut T)>
{
let mut current = entity;
let mut found = false;
while let Some(child_of) = world.get::<ChildOf>(current) {
current = child_of.parent();
let Some(component) = world.get::<T>(current) else { continue };
if !(filter)(&component) {
continue;
}
found = true;
break;
}
if found {
let component = world.get_mut::<T>(current).unwrap();
return Some((current, component.into_inner()));
}
None
}
pub fn iter_descendants_filtered(
world: &World,
entity: Entity,
filter: impl Fn(&World, Entity) -> bool,
mut callback: impl FnMut(&World, Entity),
)
{
fn iter_impl(
world: &World,
entity: Entity,
filter: &impl Fn(&World, Entity) -> bool,
callback: &mut impl FnMut(&World, Entity),
)
{
if !(*filter)(world, entity) {
return;
}
(*callback)(world, entity);
if let Some(children) = world.get::<Children>(entity) {
for child in children.iter() {
iter_impl(world, child, filter, callback);
}
}
}
iter_impl(world, entity, &filter, &mut callback)
}
#[derive(Resource, Default)]
pub struct IterChildren
{
stack: Vec<Entity>,
}
impl IterChildren
{
pub fn search<R>(
&mut self,
initial_entity: Entity,
children_query: &Query<&Children>,
search_fn: impl FnMut(Entity) -> Option<R>,
) -> Option<R>
{
self.stack.clear();
self.stack.push(initial_entity);
self.search_impl(children_query, search_fn)
}
pub fn search_descendants<R>(
&mut self,
initial_children: &Children,
children_query: &Query<&Children>,
search_fn: impl FnMut(Entity) -> Option<R>,
) -> Option<R>
{
self.stack.clear();
self.stack.extend(initial_children);
self.search_impl(children_query, search_fn)
}
pub fn search_impl<R>(
&mut self,
children_query: &Query<&Children>,
mut search_fn: impl FnMut(Entity) -> Option<R>,
) -> Option<R>
{
while let Some(entity) = self.stack.pop() {
if let Some(entry) = (search_fn)(entity) {
return Some(entry);
}
if let Ok(next_children) = children_query.get(entity) {
self.stack.extend(next_children);
}
}
None
}
}