mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 15:14:50 +00:00
Add ability to inspect entity's components (#5136)
# Objective - Provide a way to see the components of an entity. - Fixes #1467 ## Solution - Add `World::inspect_entity`. It accepts an `Entity` and returns a vector of `&ComponentInfo` that the entity has. - Add `EntityCommands::log_components`. It logs the component names of the entity. (info level) --- ## Changelog ### Added - Ability to inspect components of an entity through `World::inspect_entity` or `EntityCommands::log_components`
This commit is contained in:
parent
5f8e43833d
commit
b3fa4790b7
2 changed files with 113 additions and 3 deletions
|
@ -7,7 +7,7 @@ use crate::{
|
|||
entity::{Entities, Entity},
|
||||
world::{FromWorld, World},
|
||||
};
|
||||
use bevy_utils::tracing::{error, warn};
|
||||
use bevy_utils::tracing::{error, info, warn};
|
||||
pub use command_queue::CommandQueue;
|
||||
pub use parallel_scope::*;
|
||||
use std::marker::PhantomData;
|
||||
|
@ -588,6 +588,13 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> {
|
|||
});
|
||||
}
|
||||
|
||||
/// Logs the components of the entity at the info level.
|
||||
pub fn log_components(&mut self) {
|
||||
self.commands.add(LogComponents {
|
||||
entity: self.entity,
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns the underlying [`Commands`].
|
||||
pub fn commands(&mut self) -> &mut Commands<'w, 's> {
|
||||
self.commands
|
||||
|
@ -793,6 +800,22 @@ impl<R: Resource> Command for RemoveResource<R> {
|
|||
}
|
||||
}
|
||||
|
||||
/// [`Command`] to log the components of a given entity. See [`EntityCommands::log_components`].
|
||||
pub struct LogComponents {
|
||||
entity: Entity,
|
||||
}
|
||||
|
||||
impl Command for LogComponents {
|
||||
fn write(self, world: &mut World) {
|
||||
let debug_infos: Vec<_> = world
|
||||
.inspect_entity(self.entity)
|
||||
.into_iter()
|
||||
.map(|component_info| component_info.name())
|
||||
.collect();
|
||||
info!("Entity {:?}: {:?}", self.entity, debug_infos);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::float_cmp, clippy::approx_constant)]
|
||||
mod tests {
|
||||
|
|
|
@ -12,7 +12,8 @@ use crate::{
|
|||
bundle::{Bundle, BundleInserter, BundleSpawner, Bundles},
|
||||
change_detection::{MutUntyped, Ticks},
|
||||
component::{
|
||||
Component, ComponentDescriptor, ComponentId, ComponentTicks, Components, StorageType,
|
||||
Component, ComponentDescriptor, ComponentId, ComponentInfo, ComponentTicks, Components,
|
||||
StorageType,
|
||||
},
|
||||
entity::{AllocAtWithoutReplacement, Entities, Entity},
|
||||
query::{QueryState, WorldQuery},
|
||||
|
@ -280,6 +281,30 @@ impl World {
|
|||
.unwrap_or_else(|| panic!("Entity {:?} does not exist", entity))
|
||||
}
|
||||
|
||||
/// Returns the components of an [`Entity`](crate::entity::Entity) through [`ComponentInfo`](crate::component::ComponentInfo).
|
||||
#[inline]
|
||||
pub fn inspect_entity(&self, entity: Entity) -> Vec<&ComponentInfo> {
|
||||
let entity_location = self
|
||||
.entities()
|
||||
.get(entity)
|
||||
.unwrap_or_else(|| panic!("Entity {:?} does not exist", entity));
|
||||
|
||||
let archetype = self
|
||||
.archetypes()
|
||||
.get(entity_location.archetype_id)
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Archetype {:?} does not exist",
|
||||
entity_location.archetype_id
|
||||
)
|
||||
});
|
||||
|
||||
archetype
|
||||
.components()
|
||||
.filter_map(|id| self.components().get_info(id))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Returns an [`EntityMut`] for the given `entity` (if it exists) or spawns one if it doesn't exist.
|
||||
/// This will return [`None`] if the `entity` exists with a different generation.
|
||||
///
|
||||
|
@ -1542,11 +1567,13 @@ mod tests {
|
|||
use super::World;
|
||||
use crate::{
|
||||
change_detection::DetectChanges,
|
||||
component::{ComponentDescriptor, ComponentId, StorageType},
|
||||
component::{ComponentDescriptor, ComponentId, ComponentInfo, StorageType},
|
||||
ptr::OwningPtr,
|
||||
};
|
||||
use bevy_ecs_macros::Component;
|
||||
use bevy_utils::HashSet;
|
||||
use std::{
|
||||
any::TypeId,
|
||||
panic,
|
||||
sync::{
|
||||
atomic::{AtomicBool, AtomicU32, Ordering},
|
||||
|
@ -1762,4 +1789,64 @@ mod tests {
|
|||
world.insert_resource_by_id(invalid_component_id, ptr);
|
||||
});
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
struct Foo;
|
||||
|
||||
#[derive(Component)]
|
||||
struct Bar;
|
||||
|
||||
#[derive(Component)]
|
||||
struct Baz;
|
||||
|
||||
#[test]
|
||||
fn inspect_entity_components() {
|
||||
let mut world = World::new();
|
||||
let ent0 = world.spawn().insert_bundle((Foo, Bar, Baz)).id();
|
||||
let ent1 = world.spawn().insert_bundle((Foo, Bar)).id();
|
||||
let ent2 = world.spawn().insert_bundle((Bar, Baz)).id();
|
||||
let ent3 = world.spawn().insert_bundle((Foo, Baz)).id();
|
||||
let ent4 = world.spawn().insert_bundle((Foo,)).id();
|
||||
let ent5 = world.spawn().insert_bundle((Bar,)).id();
|
||||
let ent6 = world.spawn().insert_bundle((Baz,)).id();
|
||||
|
||||
fn to_type_ids(component_infos: Vec<&ComponentInfo>) -> HashSet<Option<TypeId>> {
|
||||
component_infos
|
||||
.into_iter()
|
||||
.map(|component_info| component_info.type_id())
|
||||
.collect()
|
||||
}
|
||||
|
||||
let foo_id = TypeId::of::<Foo>();
|
||||
let bar_id = TypeId::of::<Bar>();
|
||||
let baz_id = TypeId::of::<Baz>();
|
||||
assert_eq!(
|
||||
to_type_ids(world.inspect_entity(ent0)),
|
||||
[Some(foo_id), Some(bar_id), Some(baz_id)].into()
|
||||
);
|
||||
assert_eq!(
|
||||
to_type_ids(world.inspect_entity(ent1)),
|
||||
[Some(foo_id), Some(bar_id)].into()
|
||||
);
|
||||
assert_eq!(
|
||||
to_type_ids(world.inspect_entity(ent2)),
|
||||
[Some(bar_id), Some(baz_id)].into()
|
||||
);
|
||||
assert_eq!(
|
||||
to_type_ids(world.inspect_entity(ent3)),
|
||||
[Some(foo_id), Some(baz_id)].into()
|
||||
);
|
||||
assert_eq!(
|
||||
to_type_ids(world.inspect_entity(ent4)),
|
||||
[Some(foo_id)].into()
|
||||
);
|
||||
assert_eq!(
|
||||
to_type_ids(world.inspect_entity(ent5)),
|
||||
[Some(bar_id)].into()
|
||||
);
|
||||
assert_eq!(
|
||||
to_type_ids(world.inspect_entity(ent6)),
|
||||
[Some(baz_id)].into()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue