bevy

Get all components of entity


Is it possible to get a list of components by having Entity in bevy rust? For example for debugging purposes.

use bevy::prelude::*;
fn main()
{
    App::build()
        .add_plugins(DefaultPlugins)
        .add_startup_system(setup.system())
        .add_system(first.system())
        .add_system(first_no_second.system())
        .add_system(first_and_second.system())
        .run()
}

fn setup(mut commands: Commands)
{
    commands.spawn().insert(FirstComponent(0.0));
    commands.spawn().insert(FirstComponent(1.0));
    commands.spawn().insert(SecondComponent::StateA);
    commands.spawn().insert(SecondComponent::StateB);
    commands.spawn().insert(SecondComponent::StateA).insert(FirstComponent(3.0));
    commands.spawn().insert(SecondComponent::StateB).insert(FirstComponent(4.0));
}

#[derive(Debug)]
struct FirstComponent(f32);

#[derive(Debug)]
enum SecondComponent
{
    StateA,
    StateB
}

fn first(query: Query<&FirstComponent>)
{
    for entity in query.iter()
    {
        println!("First: {:?}", entity)
    }
}

fn first_no_second(query: Query<&FirstComponent, Without<SecondComponent>>)
{
    for entity in query.iter()
    {
        println!("First without Second: {:?}", entity)
    }
}

fn first_and_second(query: Query<&FirstComponent, With<SecondComponent>>)
{
    for entity in query.iter()
    {
        println!("First with Second: {:?}", entity)
    }
}

How bevy's ecs understands which systems need to be started for a certain Queue. Within World, the components are somehow related to the Entity, am I right? Is it possible to somehow trace this connection from the outside? I really like how it works, for me it looks like magic, but I would like to understand what is happening "under the hood"


Solution

  • I found it possible to get direct access to the world, components and entities only through AppBuilder. Below is a sample code which is sufficient for my purposes

    use bevy::prelude::*;
    use bevy::ecs::component::{ComponentId, ComponentInfo};
    
    
    fn main()
    {
        App::build()
            .add_plugin(WorldPlugin::default())
            .run()
    }
    
    // some components for test
    struct TestComponent;
    struct TestComponent2;
    
    
    #[derive(Default)]
    struct WorldPlugin {}
    
    impl Plugin for WorldPlugin
    {
        fn build(&self, app: &mut AppBuilder)
        {
            // creating an entity with both test components
            let entity = app.world_mut()
                .spawn()
                .insert(TestComponent)
                .insert(TestComponent2)
                .id();
            // to interact with components and entities you need access to the world
            let world = app.world();
            // components are stored covertly as component id
            for component_id in get_components_ids(world, &entity).unwrap()
            {
                let component_info = component_id_to_component_info(world, component_id).unwrap();
                println!("{}", extract_component_name(component_info));
            }
    
        }
    }
    
    
    /// gets an iterator component id from the world corresponding to your entity
    fn get_components_ids<'a>(world: &'a World, entity: &Entity) -> Option<impl Iterator<Item=ComponentId> + 'a>
    {
        // components and entities are linked through archetypes
        for archetype in world.archetypes().iter()
        {
            if archetype.entities().contains(entity) { return Some(archetype.components()) }
        }
        None
    }
    
    fn component_id_to_component_info(world: &World, component_id: ComponentId) -> Option<&ComponentInfo>
    {
        let components = world.components();
        components.get_info(component_id)
    }
    
    fn extract_component_name(component_info: &ComponentInfo) -> &str
    {
        component_info.name()
    }
    
    

    This code makes it possible to get a set of components for your entity, which allows you to get any data about a component. Here is a description of the ComponentInfo structure taken from the bevy source code

    #[derive(Debug)]
    pub struct ComponentInfo {
        name: String,
        id: ComponentId,
        type_id: Option<TypeId>,
        // SAFETY: This must remain private. It must only be set to "true" if this component is
        // actually Send + Sync
        is_send_and_sync: bool,
        layout: Layout,
        drop: unsafe fn(*mut u8),
        storage_type: StorageType,
    }
    

    The world stores a set of components, entities, and "archetypes" are used to link them. An example diagram is attached below. Short diagram