Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add NameLookup Type to make looking up entities by name easier #5976

Closed
wants to merge 3 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 85 additions & 1 deletion crates/bevy_animation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ use bevy_ecs::{
prelude::Component,
reflect::ReflectComponent,
schedule::ParallelSystemDescriptorCoercion,
system::{Query, Res},
system::{Query, Res, SystemParam},
query::QueryEntityError,
};
use bevy_hierarchy::Children;
use bevy_math::{Quat, Vec3};
Expand All @@ -30,6 +31,89 @@ pub mod prelude {
};
}

/// System param to enable entity lookup of an entity via EntityPath
#[derive(SystemParam)]
pub struct NameLookup<'w, 's> {
named: Query<'w, 's, (Entity, &'static Name)>,
children: Query<'w, 's, &'static Children>,
}

/// Errors when looking up an entity by name
pub enum LookupError {
/// An entity could not be found, this either means the entity has been
/// despawned, or the entity doesn't have the required components
Query(QueryEntityError),
/// The root node does not have the corrent name
// TODO: add expected / found name
RootNotFound,
/// A child was not found
// TODO: add expected name
ChildNotFound,
/// The name does not uniquely identify an entity
// TODO: add name
NameNotUnique,
}

impl From<QueryEntityError> for LookupError {
fn from(q: QueryEntityError) -> Self {
Self::Query(q)
}
}

impl<'w, 's> NameLookup<'w, 's> {
/// Find an entity by entity path, may return an error if the root name isn't unique
pub fn lookup_any(&self, path: &EntityPath) -> Result<Entity, LookupError> {
let mut path = path.parts.iter();
let root_name = path.next().unwrap();
let mut root = None;
for (entity, name) in self.named.iter() {
if root_name == name {
if root.is_some() {
return Err(LookupError::NameNotUnique);
}
the10thWiz marked this conversation as resolved.
Show resolved Hide resolved
root = Some(entity);
}
}
let mut current_node = root.ok_or(LookupError::RootNotFound)?;
for part in path {
current_node = self.find_child(current_node, part)?;
}
Ok(current_node)
the10thWiz marked this conversation as resolved.
Show resolved Hide resolved
}

/// Find an entity by the root & entity path
pub fn lookup(&self, root: Entity, path: &EntityPath) -> Result<Entity, LookupError> {
let mut path = path.parts.iter();
let (_, root_name) = self.named.get(root)?;
if root_name != path.next().unwrap() {
return Err(LookupError::RootNotFound);
}
let mut current_node = root;
for part in path {
current_node = self.find_child(current_node, part)?;
}
Ok(current_node)
the10thWiz marked this conversation as resolved.
Show resolved Hide resolved
}

/// Internal function to get the child of `current_node` that has the name `part`
fn find_child(&self, current_node: Entity, part: &Name) -> Result<Entity, LookupError> {
let children = self.children.get(current_node)?;
let mut ret = Err(LookupError::ChildNotFound);
for child in children {
if let Ok((_, name)) = self.named.get(*child) {
if name == part {
if ret.is_ok() {
return Err(LookupError::NameNotUnique);
}
ret = Ok(*child);
}
}
}
ret
}
}


/// List of keyframes for one of the attribute of a [`Transform`].
#[derive(Clone, Debug)]
pub enum Keyframes {
Expand Down