From 33f69120ab50d31cd5d2128343a8a50b556594f7 Mon Sep 17 00:00:00 2001 From: harudagondi Date: Wed, 29 Jun 2022 18:23:53 +0800 Subject: [PATCH 1/7] Add ability to inspect entity's components --- crates/bevy_ecs/src/system/commands/mod.rs | 21 +++++- crates/bevy_ecs/src/world/mod.rs | 77 +++++++++++++++++++++- 2 files changed, 95 insertions(+), 3 deletions(-) diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index bf40e13fb98b1..52700d88ffa0d 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -7,7 +7,7 @@ use crate::{ entity::{Entities, Entity}, world::{FromWorld, World}, }; -use bevy_utils::tracing::{error, warn}; +use bevy_utils::tracing::{debug, error, warn}; pub use command_queue::CommandQueue; pub use parallel_scope::*; use std::marker::PhantomData; @@ -217,6 +217,11 @@ impl<'w, 's> Commands<'w, 's> { } } + /// Logs the components of a given entity at the debug level. + pub fn debug_entity(&mut self, entity: Entity) { + self.queue.push(DebugEntity { entity }); + } + /// Spawns entities to the [`World`] according to the given iterator (or a type that can /// be converted to it). /// @@ -793,6 +798,20 @@ impl Command for RemoveResource { } } +pub struct DebugEntity { + entity: Entity, +} + +impl Command for DebugEntity { + fn write(self, world: &mut World) { + debug!( + "Entity {:?}: {:?}", + self.entity, + world.inspect_entity(self.entity) + ); + } +} + #[cfg(test)] #[allow(clippy::float_cmp, clippy::approx_constant)] mod tests { diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 5c75740f7bdfa..d559b30f26b20 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -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,16 @@ 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(&mut self, entity: Entity) -> Vec<&ComponentInfo> { + let entity_ref = self.entity(entity); + self.components() + .iter() + .filter(|component| entity_ref.contains_id(component.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 +1553,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 +1775,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> { + component_infos + .into_iter() + .map(|component_info| component_info.type_id()) + .collect() + } + + let foo_id = TypeId::of::(); + let bar_id = TypeId::of::(); + let baz_id = TypeId::of::(); + 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() + ); + } } From 5e1dd6a425da12800cbaff54c6e18e4df164a8f5 Mon Sep 17 00:00:00 2001 From: harudagondi Date: Wed, 29 Jun 2022 21:09:45 +0800 Subject: [PATCH 2/7] Added docs for `DebugEntity` --- crates/bevy_ecs/src/system/commands/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index 52700d88ffa0d..81bc055611c85 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -798,6 +798,7 @@ impl Command for RemoveResource { } } +/// [`Command`] to log the components of a given entity. See [`Commands::debug_entity`]. pub struct DebugEntity { entity: Entity, } From c99770e4d306e692cae68eb67856dd9ff061f110 Mon Sep 17 00:00:00 2001 From: harudagondi Date: Wed, 29 Jun 2022 21:30:27 +0800 Subject: [PATCH 3/7] Change `inspect_entity()` to optimized version --- crates/bevy_ecs/src/world/mod.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index d559b30f26b20..b43161407dab5 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -284,10 +284,24 @@ impl World { /// Returns the components of an [`Entity`](crate::entity::Entity) through [`ComponentInfo`](crate::component::ComponentInfo). #[inline] pub fn inspect_entity(&mut self, entity: Entity) -> Vec<&ComponentInfo> { - let entity_ref = self.entity(entity); - self.components() - .iter() - .filter(|component| entity_ref.contains_id(component.id())) + 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() } From 8b70f7dbec303112deae7c87dcf66f5f2ebd285a Mon Sep 17 00:00:00 2001 From: harudagondi Date: Thu, 30 Jun 2022 00:00:23 +0800 Subject: [PATCH 4/7] Refactor `debug_entity()` to `log_components()` - Simplified log output to show only the name. - moved the function to `EntityCommands` - change log level to INFO --- crates/bevy_ecs/src/system/commands/mod.rs | 27 ++++++++++++---------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index 81bc055611c85..16c0faa1f1d69 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -7,7 +7,7 @@ use crate::{ entity::{Entities, Entity}, world::{FromWorld, World}, }; -use bevy_utils::tracing::{debug, error, warn}; +use bevy_utils::tracing::{error, info, warn}; pub use command_queue::CommandQueue; pub use parallel_scope::*; use std::marker::PhantomData; @@ -217,11 +217,6 @@ impl<'w, 's> Commands<'w, 's> { } } - /// Logs the components of a given entity at the debug level. - pub fn debug_entity(&mut self, entity: Entity) { - self.queue.push(DebugEntity { entity }); - } - /// Spawns entities to the [`World`] according to the given iterator (or a type that can /// be converted to it). /// @@ -593,6 +588,13 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> { }); } + /// Logs the components of the entity at the debug level. + pub fn log_components(&mut self) { + self.commands.add(DebugEntity { + entity: self.entity, + }); + } + /// Returns the underlying [`Commands`]. pub fn commands(&mut self) -> &mut Commands<'w, 's> { self.commands @@ -798,18 +800,19 @@ impl Command for RemoveResource { } } -/// [`Command`] to log the components of a given entity. See [`Commands::debug_entity`]. +/// [`Command`] to log the components of a given entity. See [`EntityCommands::log_components`]. pub struct DebugEntity { entity: Entity, } impl Command for DebugEntity { fn write(self, world: &mut World) { - debug!( - "Entity {:?}: {:?}", - self.entity, - world.inspect_entity(self.entity) - ); + let debug_infos: Vec<_> = world + .inspect_entity(self.entity) + .into_iter() + .map(|component_info| component_info.name()) + .collect(); + info!("Entity {:?}: {:?}", self.entity, debug_infos); } } From 67551f96abb1a08c4a18fedbd5968ba1da791a75 Mon Sep 17 00:00:00 2001 From: harudagondi Date: Thu, 30 Jun 2022 00:07:17 +0800 Subject: [PATCH 5/7] Quick doc fix --- crates/bevy_ecs/src/system/commands/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index 16c0faa1f1d69..8fd6f225302de 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -588,7 +588,7 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> { }); } - /// Logs the components of the entity at the debug level. + /// Logs the components of the entity at the info level. pub fn log_components(&mut self) { self.commands.add(DebugEntity { entity: self.entity, From 357ed9968c53beb24c7311cc1cf13183e8be7216 Mon Sep 17 00:00:00 2001 From: harudagondi Date: Thu, 30 Jun 2022 00:26:54 +0800 Subject: [PATCH 6/7] Change `&mut self` to `&self` in `inspect_entity()` --- crates/bevy_ecs/src/world/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index b43161407dab5..5f4a952e62c35 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -283,7 +283,7 @@ impl World { /// Returns the components of an [`Entity`](crate::entity::Entity) through [`ComponentInfo`](crate::component::ComponentInfo). #[inline] - pub fn inspect_entity(&mut self, entity: Entity) -> Vec<&ComponentInfo> { + pub fn inspect_entity(&self, entity: Entity) -> Vec<&ComponentInfo> { let entity_location = self .entities() .get(entity) From 5dfe553a609a598a723243b5f54b0640e7540a9a Mon Sep 17 00:00:00 2001 From: harudagondi Date: Thu, 30 Jun 2022 10:08:38 +0800 Subject: [PATCH 7/7] Rename `DebugEntity` to `LogComponents` --- crates/bevy_ecs/src/system/commands/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index 8fd6f225302de..aafaf45f276b0 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -590,7 +590,7 @@ 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(DebugEntity { + self.commands.add(LogComponents { entity: self.entity, }); } @@ -801,11 +801,11 @@ impl Command for RemoveResource { } /// [`Command`] to log the components of a given entity. See [`EntityCommands::log_components`]. -pub struct DebugEntity { +pub struct LogComponents { entity: Entity, } -impl Command for DebugEntity { +impl Command for LogComponents { fn write(self, world: &mut World) { let debug_infos: Vec<_> = world .inspect_entity(self.entity)