# Objective
We should have an API with filtering to allow BRP clients to retrieve
all relevant data from the world state. Currently working on adding
examples - but reviews are appreciated! Still semi-WIP while I get my
head around bevy’s reflection and implementation :)
## Solution
This change adds support to query all entities in the world, and returns
all of their Reflected Components with corresponding values. For custom
`Components` it's important to still implement `Reflect` so that this
endpoint returns these. This will be useful for the
`bevy_entity_inspector` so that we can easily get the current world
state. We have modified the existing query API
so that clients can now pass in an empty `components[]` on the JSON
request.
## Testing
Updated example to showcase how to use the new endpoint to get all data:
```rust
/// Create a query_all request to send to the remote Bevy app.
/// This request will return all entities in the app, their components, and their
/// component values.
fn run_query_all_components_and_entities(url: String) -> Result<(), anyhow::Error> {
    let query_all_req = BrpRequest {
        jsonrpc: String::from("2.0"),
        method: String::from(BRP_QUERY_METHOD),
        id: Some(serde_json::to_value(1)?),
        params: None,
    };
    println!("query_all req: {:#?}", query_all_req);
    let query_all_res = ureq::post(&url)
        .send_json(query_all_req)?
        .body_mut()
        .read_json::<serde_json::Value>()?;
    println!("{query_all_res:#}");
    Ok(())
}
```
---
## Showcase
In the `client.rs` example, we can clearly see (assuming the `server.rs`
is running) a query hit for all entities and components:
```text
query_all req: BrpRequest {
    jsonrpc: "2.0",
    method: "bevy/query",
    id: Some(
        Number(1),
    ),
    params: Some(
        Object {
            "data": Object {
                "components": Array [],
                "has": Array [],
                "option": Array [],
            },
            "filter": Object {
                "with": Array [],
                "without": Array [],
            },
            "strict": Bool(false),
        },
    ),
}
```
And in the massive response:
```text
.....
{
      "components": {
        "bevy_window::monitor::Monitor": {
          "name": "\\\\.\\DISPLAY1",
          "physical_height": 1080,
          "physical_position": [
            -1920,
            0
          ],
          "physical_width": 1920,
          "refresh_rate_millihertz": 240000,
          "scale_factor": 1.25,
          "video_modes": [
            {
              "bit_depth": 32,
              "physical_size": [
                1920,
                1080
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1680,
                1050
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1600,
                900
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1440,
                900
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1400,
                1050
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1366,
                768
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1360,
                768
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1280,
                1024
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1280,
                960
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1280,
                800
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1280,
                768
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1280,
                720
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1280,
                600
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1152,
                864
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1024,
                768
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                800,
                600
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                640,
                480
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                640,
                400
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                512,
                384
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                400,
                300
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                320,
                240
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                320,
                200
              ],
              "refresh_rate_millihertz": 240000
            }
          ]
        }
      },
      "entity": 4294967267
    },
....
```
What's also really cool about this and `bevy_reflect` is that we also
get custom components returned as well (see below for `"server::Cube":
1.0` as the custom reflected struct specified in `server.rs`:
```text
{
      "components": {
        "bevy_render::primitives::Aabb": {
          "center": [
            0.0,
            0.0,
            0.0
          ],
          "half_extents": [
            0.5,
            0.5,
            0.5
          ]
        },
        "bevy_render::view::visibility::InheritedVisibility": true,
        "bevy_render::view::visibility::ViewVisibility": true,
        "bevy_render::view::visibility::Visibility": "Inherited",
        "bevy_transform::components::global_transform::GlobalTransform": [
          1.0,
          0.0,
          0.0,
          0.0,
          1.0,
          0.0,
          0.0,
          0.0,
          1.0,
          0.0,
          2.4572744369506836,
          0.0
        ],
        "bevy_transform::components::transform::Transform": {
          "rotation": [
            0.0,
            0.0,
            0.0,
            1.0
          ],
          "scale": [
            1.0,
            1.0,
            1.0
          ],
          "translation": [
            0.0,
            2.4572744369506836,
            0.0
          ]
        },
        "bevy_transform::components::transform::TransformTreeChanged": null,
        "server::Cube": 1.0
      },
```
---------
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
		
	
			
		
			
				
	
	
		
			129 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			129 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
//! A simple command line client that allows issuing queries to a remote Bevy
 | 
						|
//! app via the BRP.
 | 
						|
//! This example requires the `bevy_remote` feature to be enabled.
 | 
						|
//! You can run it with the following command:
 | 
						|
//! ```text
 | 
						|
//! cargo run --example client --features="bevy_remote"
 | 
						|
//! ```
 | 
						|
//! This example assumes that the `server` example is running on the same machine.
 | 
						|
 | 
						|
use std::any::type_name;
 | 
						|
 | 
						|
use anyhow::Result as AnyhowResult;
 | 
						|
use bevy::{
 | 
						|
    ecs::hierarchy::ChildOf,
 | 
						|
    prelude::info,
 | 
						|
    remote::{
 | 
						|
        builtin_methods::{
 | 
						|
            BrpQuery, BrpQueryFilter, BrpQueryParams, ComponentSelector, BRP_QUERY_METHOD,
 | 
						|
        },
 | 
						|
        http::{DEFAULT_ADDR, DEFAULT_PORT},
 | 
						|
        BrpRequest,
 | 
						|
    },
 | 
						|
    transform::components::Transform,
 | 
						|
};
 | 
						|
 | 
						|
/// The application entry point.
 | 
						|
fn main() -> AnyhowResult<()> {
 | 
						|
    // Create the URL. We're going to need it to issue the HTTP request.
 | 
						|
    let host_part = format!("{DEFAULT_ADDR}:{DEFAULT_PORT}");
 | 
						|
    let url = format!("http://{host_part}/");
 | 
						|
    // Creates a request to get all Transform components from the remote Bevy app.
 | 
						|
    // This request will return all entities that have a Transform component.
 | 
						|
    run_transform_only_query(&url)?;
 | 
						|
 | 
						|
    // Create a query that only returns root entities - ie, entities that do not
 | 
						|
    // have a parent.
 | 
						|
    run_query_root_entities(&url)?;
 | 
						|
 | 
						|
    // Create a query all request to send to the remote Bevy app.
 | 
						|
    // This request will return all entities in the app, their components, and their
 | 
						|
    // component values.
 | 
						|
    run_query_all_components_and_entities(&url)?;
 | 
						|
 | 
						|
    Ok(())
 | 
						|
}
 | 
						|
 | 
						|
fn run_query_all_components_and_entities(url: &str) -> Result<(), anyhow::Error> {
 | 
						|
    let query_all_req = BrpRequest {
 | 
						|
        jsonrpc: String::from("2.0"),
 | 
						|
        method: String::from(BRP_QUERY_METHOD),
 | 
						|
        id: Some(serde_json::to_value(1)?),
 | 
						|
        params: Some(
 | 
						|
            serde_json::to_value(BrpQueryParams {
 | 
						|
                data: BrpQuery {
 | 
						|
                    components: Vec::default(),
 | 
						|
                    option: ComponentSelector::All,
 | 
						|
                    has: Vec::default(),
 | 
						|
                },
 | 
						|
                strict: false,
 | 
						|
                filter: BrpQueryFilter::default(),
 | 
						|
            })
 | 
						|
            .expect("Unable to convert query parameters to a valid JSON value"),
 | 
						|
        ),
 | 
						|
    };
 | 
						|
    info!("query_all req: {query_all_req:#?}");
 | 
						|
    let query_all_res = ureq::post(url)
 | 
						|
        .send_json(query_all_req)?
 | 
						|
        .body_mut()
 | 
						|
        .read_json::<serde_json::Value>()?;
 | 
						|
    info!("{query_all_res:#}");
 | 
						|
    Ok(())
 | 
						|
}
 | 
						|
 | 
						|
fn run_transform_only_query(url: &str) -> Result<(), anyhow::Error> {
 | 
						|
    let get_transform_request = BrpRequest {
 | 
						|
        jsonrpc: String::from("2.0"),
 | 
						|
        method: String::from(BRP_QUERY_METHOD),
 | 
						|
        id: Some(serde_json::to_value(1)?),
 | 
						|
        params: Some(
 | 
						|
            serde_json::to_value(BrpQueryParams {
 | 
						|
                data: BrpQuery {
 | 
						|
                    components: vec![type_name::<Transform>().to_string()],
 | 
						|
                    ..Default::default()
 | 
						|
                },
 | 
						|
                strict: false,
 | 
						|
                filter: BrpQueryFilter::default(),
 | 
						|
            })
 | 
						|
            .expect("Unable to convert query parameters to a valid JSON value"),
 | 
						|
        ),
 | 
						|
    };
 | 
						|
    info!("transform request: {get_transform_request:#?}");
 | 
						|
    let res = ureq::post(url)
 | 
						|
        .send_json(get_transform_request)?
 | 
						|
        .body_mut()
 | 
						|
        .read_json::<serde_json::Value>()?;
 | 
						|
    info!("{res:#}");
 | 
						|
    Ok(())
 | 
						|
}
 | 
						|
 | 
						|
fn run_query_root_entities(url: &str) -> Result<(), anyhow::Error> {
 | 
						|
    let get_transform_request = BrpRequest {
 | 
						|
        jsonrpc: String::from("2.0"),
 | 
						|
        method: String::from(BRP_QUERY_METHOD),
 | 
						|
        id: Some(serde_json::to_value(1)?),
 | 
						|
        params: Some(
 | 
						|
            serde_json::to_value(BrpQueryParams {
 | 
						|
                data: BrpQuery {
 | 
						|
                    components: Vec::default(),
 | 
						|
                    option: ComponentSelector::All,
 | 
						|
                    has: Vec::default(),
 | 
						|
                },
 | 
						|
                strict: false,
 | 
						|
                filter: BrpQueryFilter {
 | 
						|
                    without: vec![type_name::<ChildOf>().to_string()],
 | 
						|
                    with: Vec::default(),
 | 
						|
                },
 | 
						|
            })
 | 
						|
            .expect("Unable to convert query parameters to a valid JSON value"),
 | 
						|
        ),
 | 
						|
    };
 | 
						|
    info!("transform request: {get_transform_request:#?}");
 | 
						|
    let res = ureq::post(url)
 | 
						|
        .send_json(get_transform_request)?
 | 
						|
        .body_mut()
 | 
						|
        .read_json::<serde_json::Value>()?;
 | 
						|
    info!("{res:#}");
 | 
						|
    Ok(())
 | 
						|
}
 |