Skip to main content

bevy_remote/
builtin_methods.rs

1//! Built-in verbs for the Bevy Remote Protocol.
2
3use core::any::TypeId;
4
5use anyhow::{anyhow, Result as AnyhowResult};
6use bevy_ecs::{
7    component::ComponentId,
8    entity::Entity,
9    hierarchy::ChildOf,
10    lifecycle::RemovedComponentEntity,
11    message::MessageCursor,
12    query::QueryBuilder,
13    reflect::{AppTypeRegistry, ReflectComponent, ReflectEvent, ReflectResource},
14    system::{In, Local},
15    world::{EntityRef, EntityWorldMut, FilteredEntityRef, Mut, World},
16};
17use bevy_log::warn_once;
18use bevy_platform::collections::HashMap;
19use bevy_reflect::{
20    serde::{ReflectSerializer, TypedReflectDeserializer},
21    DynamicStruct, GetPath, PartialReflect, TypeRegistration, TypeRegistry,
22};
23use serde::{de::DeserializeSeed as _, de::IntoDeserializer, Deserialize, Serialize};
24use serde_json::{Map, Value};
25
26use crate::{
27    error_codes,
28    schemas::{
29        json_schema::{export_type, JsonSchemaBevyType},
30        open_rpc::OpenRpcDocument,
31    },
32    BrpError, BrpResult,
33};
34
35#[cfg(all(feature = "http", not(target_family = "wasm")))]
36use {crate::schemas::open_rpc::ServerObject, bevy_utils::default};
37
38/// The method path for a `world.get_components` request.
39pub const BRP_GET_COMPONENTS_METHOD: &str = "world.get_components";
40
41/// The method path for a `world.query` request.
42pub const BRP_QUERY_METHOD: &str = "world.query";
43
44/// The method path for a `world.spawn_entity` request.
45pub const BRP_SPAWN_ENTITY_METHOD: &str = "world.spawn_entity";
46
47/// The method path for a `world.insert_components` request.
48pub const BRP_INSERT_COMPONENTS_METHOD: &str = "world.insert_components";
49
50/// The method path for a `world.remove_components` request.
51pub const BRP_REMOVE_COMPONENTS_METHOD: &str = "world.remove_components";
52
53/// The method path for a `world.despawn_entity` request.
54pub const BRP_DESPAWN_COMPONENTS_METHOD: &str = "world.despawn_entity";
55
56/// The method path for a `world.reparent_entities` request.
57pub const BRP_REPARENT_ENTITIES_METHOD: &str = "world.reparent_entities";
58
59/// The method path for a `world.list_components` request.
60pub const BRP_LIST_COMPONENTS_METHOD: &str = "world.list_components";
61
62/// The method path for a `world.mutate_components` request.
63pub const BRP_MUTATE_COMPONENTS_METHOD: &str = "world.mutate_components";
64
65/// The method path for a `world.get_components+watch` request.
66pub const BRP_GET_COMPONENTS_AND_WATCH_METHOD: &str = "world.get_components+watch";
67
68/// The method path for a `world.list_components+watch` request.
69pub const BRP_LIST_COMPONENTS_AND_WATCH_METHOD: &str = "world.list_components+watch";
70
71/// The method path for a `world.get_resources` request.
72pub const BRP_GET_RESOURCE_METHOD: &str = "world.get_resources";
73
74/// The method path for a `world.insert_resources` request.
75pub const BRP_INSERT_RESOURCE_METHOD: &str = "world.insert_resources";
76
77/// The method path for a `world.remove_resources` request.
78pub const BRP_REMOVE_RESOURCE_METHOD: &str = "world.remove_resources";
79
80/// The method path for a `world.mutate_resources` request.
81pub const BRP_MUTATE_RESOURCE_METHOD: &str = "world.mutate_resources";
82
83/// The method path for a `world.list_resources` request.
84pub const BRP_LIST_RESOURCES_METHOD: &str = "world.list_resources";
85
86/// The method path for a `world.trigger_event` request.
87pub const BRP_TRIGGER_EVENT_METHOD: &str = "world.trigger_event";
88
89/// The method path for a `registry.schema` request.
90pub const BRP_REGISTRY_SCHEMA_METHOD: &str = "registry.schema";
91
92/// The method path for a `rpc.discover` request.
93pub const RPC_DISCOVER_METHOD: &str = "rpc.discover";
94
95/// `world.get_components`: Retrieves one or more components from the entity with the given
96/// ID.
97///
98/// The server responds with a [`BrpGetComponentsResponse`].
99#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
100pub struct BrpGetComponentsParams {
101    /// The ID of the entity from which components are to be requested.
102    pub entity: Entity,
103
104    /// The [full paths] of the component types that are to be requested
105    /// from the entity.
106    ///
107    /// Note that these strings must consist of the *full* type paths: e.g.
108    /// `bevy_transform::components::transform::Transform`, not just
109    /// `Transform`.
110    ///
111    /// [full paths]: bevy_reflect::TypePath::type_path
112    pub components: Vec<String>,
113
114    /// An optional flag to fail when encountering an invalid component rather
115    /// than skipping it. Defaults to false.
116    #[serde(default)]
117    pub strict: bool,
118}
119
120/// `world.get_resources`: Retrieves the value of a given resource.
121#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
122pub struct BrpGetResourcesParams {
123    /// The [full path] of the resource type being requested.
124    ///
125    /// [full path]: bevy_reflect::TypePath::type_path
126    pub resource: String,
127}
128
129/// `world.query`: Performs a query over components in the ECS, returning entities
130/// and component values that match.
131///
132/// The server responds with a [`BrpQueryResponse`].
133#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
134pub struct BrpQueryParams {
135    /// The components to select.
136    pub data: BrpQuery,
137
138    /// An optional filter that specifies which entities to include or
139    /// exclude from the results.
140    #[serde(default)]
141    pub filter: BrpQueryFilter,
142
143    /// An optional flag to fail when encountering an invalid component rather
144    /// than skipping it. Defaults to false.
145    #[serde(default)]
146    pub strict: bool,
147}
148
149/// `world.spawn_entity`: Creates a new entity with the given components and responds
150/// with its ID.
151///
152/// The server responds with a [`BrpSpawnEntityResponse`].
153#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
154pub struct BrpSpawnEntityParams {
155    /// A map from each component's full path to its serialized value.
156    ///
157    /// These components will be added to the entity.
158    ///
159    /// Note that the keys of the map must be the [full type paths]: e.g.
160    /// `bevy_transform::components::transform::Transform`, not just
161    /// `Transform`.
162    ///
163    /// [full type paths]: bevy_reflect::TypePath::type_path
164    pub components: HashMap<String, Value>,
165}
166
167/// `world.despawn_entity`: Given an ID, despawns the entity with that ID.
168///
169/// The server responds with an okay.
170#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
171pub struct BrpDespawnEntityParams {
172    /// The ID of the entity to despawn.
173    pub entity: Entity,
174}
175
176/// `world.remove_components`: Deletes one or more components from an entity.
177///
178/// The server responds with a null.
179#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
180pub struct BrpRemoveComponentsParams {
181    /// The ID of the entity from which components are to be removed.
182    pub entity: Entity,
183
184    /// The full paths of the component types that are to be removed from
185    /// the entity.
186    ///
187    /// Note that these strings must consist of the [full type paths]: e.g.
188    /// `bevy_transform::components::transform::Transform`, not just
189    /// `Transform`.
190    ///
191    /// [full type paths]: bevy_reflect::TypePath::type_path
192    pub components: Vec<String>,
193}
194
195/// `world.remove_resources`: Removes the given resource from the world.
196#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
197pub struct BrpRemoveResourcesParams {
198    /// The [full path] of the resource type to remove.
199    ///
200    /// [full path]: bevy_reflect::TypePath::type_path
201    pub resource: String,
202}
203
204/// `world.insert_components`: Adds one or more components to an entity.
205///
206/// The server responds with a null.
207#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
208pub struct BrpInsertComponentsParams {
209    /// The ID of the entity that components are to be added to.
210    pub entity: Entity,
211
212    /// A map from each component's full path to its serialized value.
213    ///
214    /// These components will be added to the entity.
215    ///
216    /// Note that the keys of the map must be the [full type paths]: e.g.
217    /// `bevy_transform::components::transform::Transform`, not just
218    /// `Transform`.
219    ///
220    /// [full type paths]: bevy_reflect::TypePath::type_path
221    pub components: HashMap<String, Value>,
222}
223
224/// `world.insert_resources`: Inserts a resource into the world with a given
225/// value.
226#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
227pub struct BrpInsertResourcesParams {
228    /// The [full path] of the resource type to insert.
229    ///
230    /// [full path]: bevy_reflect::TypePath::type_path
231    pub resource: String,
232
233    /// The serialized value of the resource to be inserted.
234    pub value: Value,
235}
236
237/// `world.reparent_entities`: Assign a new parent to one or more entities.
238///
239/// The server responds with a null.
240#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
241pub struct BrpReparentEntitiesParams {
242    /// The IDs of the entities that are to become the new children of the
243    /// `parent`.
244    pub entities: Vec<Entity>,
245
246    /// The IDs of the entity that will become the new parent of the
247    /// `entities`.
248    ///
249    /// If this is `None`, then the entities are removed from all parents.
250    #[serde(default)]
251    pub parent: Option<Entity>,
252}
253
254/// `world.list_components`: Returns a list of all type names of registered components in the
255/// system (no params provided), or those on an entity (params provided).
256///
257/// The server responds with a [`BrpListComponentsResponse`]
258#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
259pub struct BrpListComponentsParams {
260    /// The entity to query.
261    pub entity: Entity,
262}
263
264/// `world.mutate_components`:
265///
266/// The server responds with a null.
267#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
268pub struct BrpMutateComponentsParams {
269    /// The entity of the component to mutate.
270    pub entity: Entity,
271
272    /// The [full path] of the component to mutate.
273    ///
274    /// [full path]: bevy_reflect::TypePath::type_path
275    pub component: String,
276
277    /// The [path] of the field within the component.
278    ///
279    /// [path]: bevy_reflect::GetPath
280    pub path: String,
281
282    /// The value to insert at `path`.
283    pub value: Value,
284}
285
286/// `world.mutate_resources`:
287///
288/// The server responds with a null.
289#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
290pub struct BrpMutateResourcesParams {
291    /// The [full path] of the resource to mutate.
292    ///
293    /// [full path]: bevy_reflect::TypePath::type_path
294    pub resource: String,
295
296    /// The [path] of the field within the resource.
297    ///
298    /// [path]: bevy_reflect::GetPath
299    pub path: String,
300
301    /// The value to insert at `path`.
302    pub value: Value,
303}
304
305/// `world.trigger_event`:
306///
307/// The server responds with a null.
308#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
309struct BrpTriggerEventParams {
310    /// The [full path] of the event to trigger.
311    ///
312    /// [full path]: bevy_reflect::TypePath::type_path
313    pub event: String,
314    /// The serialized value of the event to be triggered, if any.
315    pub value: Option<Value>,
316}
317
318/// Describes the data that is to be fetched in a query.
319#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq)]
320pub struct BrpQuery {
321    /// The [full path] of the type name of each component that is to be
322    /// fetched.
323    ///
324    /// [full path]: bevy_reflect::TypePath::type_path
325    #[serde(default)]
326    pub components: Vec<String>,
327
328    /// The [full path] of the type name of each component that is to be
329    /// optionally fetched.
330    ///
331    /// [full path]: bevy_reflect::TypePath::type_path
332    #[serde(default)]
333    pub option: ComponentSelector,
334
335    /// The [full path] of the type name of each component that is to be checked
336    /// for presence.
337    ///
338    /// [full path]: bevy_reflect::TypePath::type_path
339    #[serde(default)]
340    pub has: Vec<String>,
341}
342
343/// Additional constraints that can be placed on a query to include or exclude
344/// certain entities.
345#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq)]
346pub struct BrpQueryFilter {
347    /// The [full path] of the type name of each component that must not be
348    /// present on the entity for it to be included in the results.
349    ///
350    /// [full path]: bevy_reflect::TypePath::type_path
351    #[serde(default)]
352    pub without: Vec<String>,
353
354    /// The [full path] of the type name of each component that must be present
355    /// on the entity for it to be included in the results.
356    ///
357    /// [full path]: bevy_reflect::TypePath::type_path
358    #[serde(default)]
359    pub with: Vec<String>,
360}
361
362/// Constraints that can be placed on a query to include or exclude
363/// certain definitions.
364#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq)]
365pub struct BrpJsonSchemaQueryFilter {
366    /// The crate name of the type name of each component that must not be
367    /// present on the entity for it to be included in the results.
368    #[serde(skip_serializing_if = "Vec::is_empty", default)]
369    pub without_crates: Vec<String>,
370
371    /// The crate name of the type name of each component that must be present
372    /// on the entity for it to be included in the results.
373    #[serde(skip_serializing_if = "Vec::is_empty", default)]
374    pub with_crates: Vec<String>,
375
376    /// Constrain resource by type
377    #[serde(default)]
378    pub type_limit: JsonSchemaTypeLimit,
379}
380
381/// Additional [`BrpJsonSchemaQueryFilter`] constraints that can be placed on a query to include or exclude
382/// certain definitions.
383#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq)]
384pub struct JsonSchemaTypeLimit {
385    /// Schema cannot have specified reflect types
386    #[serde(skip_serializing_if = "Vec::is_empty", default)]
387    pub without: Vec<String>,
388
389    /// Schema needs to have specified reflect types
390    #[serde(skip_serializing_if = "Vec::is_empty", default)]
391    pub with: Vec<String>,
392}
393
394/// A response from the world to the client that specifies a single entity.
395///
396/// This is sent in response to `world.spawn_entity`.
397#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
398pub struct BrpSpawnEntityResponse {
399    /// The ID of the entity in question.
400    pub entity: Entity,
401}
402
403/// The response to a `world.get_components` request.
404#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
405#[serde(untagged)]
406pub enum BrpGetComponentsResponse {
407    /// The non-strict response that reports errors separately without failing the entire request.
408    Lenient {
409        /// A map of successful components with their values.
410        components: HashMap<String, Value>,
411        /// A map of unsuccessful components with their errors.
412        errors: HashMap<String, Value>,
413    },
414    /// The strict response that will fail if any components are not present or aren't
415    /// reflect-able.
416    Strict(HashMap<String, Value>),
417}
418
419/// The response to a `world.get_resources` request.
420#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
421pub struct BrpGetResourcesResponse {
422    /// The value of the requested resource.
423    pub value: Value,
424}
425
426/// A single response from a `world.get_components+watch` request.
427#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
428#[serde(untagged)]
429pub enum BrpGetComponentsWatchingResponse {
430    /// The non-strict response that reports errors separately without failing the entire request.
431    Lenient {
432        /// A map of successful components with their values that were added or changes in the last
433        /// tick.
434        components: HashMap<String, Value>,
435        /// An array of components that were been removed in the last tick.
436        removed: Vec<String>,
437        /// A map of unsuccessful components with their errors.
438        errors: HashMap<String, Value>,
439    },
440    /// The strict response that will fail if any components are not present or aren't
441    /// reflect-able.
442    Strict {
443        /// A map of successful components with their values that were added or changes in the last
444        /// tick.
445        components: HashMap<String, Value>,
446        /// An array of components that were been removed in the last tick.
447        removed: Vec<String>,
448    },
449}
450
451/// The response to a `world.list_components` request.
452pub type BrpListComponentsResponse = Vec<String>;
453
454/// The response to a `world.list_resources` request.
455pub type BrpListResourcesResponse = Vec<String>;
456
457/// A single response from a `world.list_components+watch` request.
458#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
459pub struct BrpListComponentsWatchingResponse {
460    added: Vec<String>,
461    removed: Vec<String>,
462}
463
464/// The response to a `world.query` request.
465pub type BrpQueryResponse = Vec<BrpQueryRow>;
466
467/// One query match result: a single entity paired with the requested components.
468#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
469pub struct BrpQueryRow {
470    /// The ID of the entity that matched.
471    pub entity: Entity,
472
473    /// The serialized values of the requested components.
474    pub components: HashMap<String, Value>,
475
476    /// The boolean-only containment query results.
477    #[serde(skip_serializing_if = "HashMap::is_empty", default)]
478    pub has: HashMap<String, Value>,
479}
480
481/// A helper function used to parse a `serde_json::Value`.
482pub fn parse<T: for<'de> Deserialize<'de>>(value: Value) -> Result<T, BrpError> {
483    serde_json::from_value(value).map_err(|err| BrpError {
484        code: error_codes::INVALID_PARAMS,
485        message: err.to_string(),
486        data: None,
487    })
488}
489
490/// A helper function used to parse a `serde_json::Value` wrapped in an `Option`.
491pub fn parse_some<T: for<'de> Deserialize<'de>>(value: Option<Value>) -> Result<T, BrpError> {
492    match value {
493        Some(value) => parse(value),
494        None => Err(BrpError {
495            code: error_codes::INVALID_PARAMS,
496            message: String::from("Params not provided"),
497            data: None,
498        }),
499    }
500}
501
502/// Handles a `world.get_components` request coming from a client.
503pub fn process_remote_get_components_request(
504    In(params): In<Option<Value>>,
505    world: &World,
506) -> BrpResult {
507    let BrpGetComponentsParams {
508        entity,
509        components,
510        strict,
511    } = parse_some(params)?;
512
513    let app_type_registry = world.resource::<AppTypeRegistry>();
514    let type_registry = app_type_registry.read();
515    let entity_ref = get_entity(world, entity)?;
516
517    let response =
518        reflect_components_to_response(components, strict, entity, entity_ref, &type_registry)?;
519    serde_json::to_value(response).map_err(BrpError::internal)
520}
521
522/// Handles a `world.get_resources` request coming from a client.
523pub fn process_remote_get_resources_request(
524    In(params): In<Option<Value>>,
525    world: &World,
526) -> BrpResult {
527    let BrpGetResourcesParams {
528        resource: resource_path,
529    } = parse_some(params)?;
530
531    let app_type_registry = world.resource::<AppTypeRegistry>();
532    let type_registry = app_type_registry.read();
533    let reflect_resource =
534        get_reflect_resource(&type_registry, &resource_path).map_err(BrpError::resource_error)?;
535
536    let Ok(reflected) = reflect_resource.reflect(world) else {
537        return Err(BrpError::resource_not_present(&resource_path));
538    };
539
540    // Use the `ReflectSerializer` to serialize the value of the resource;
541    // this produces a map with a single item.
542    let reflect_serializer = ReflectSerializer::new(reflected.as_partial_reflect(), &type_registry);
543    let Value::Object(serialized_object) =
544        serde_json::to_value(&reflect_serializer).map_err(BrpError::resource_error)?
545    else {
546        return Err(BrpError {
547            code: error_codes::RESOURCE_ERROR,
548            message: format!("Resource `{resource_path}` could not be serialized"),
549            data: None,
550        });
551    };
552
553    // Get the single value out of the map.
554    let value = serialized_object.into_values().next().ok_or_else(|| {
555        BrpError::internal(anyhow!("Unexpected format of serialized resource value"))
556    })?;
557    let response = BrpGetResourcesResponse { value };
558    serde_json::to_value(response).map_err(BrpError::internal)
559}
560
561/// Handles a `world.get_components+watch` request coming from a client.
562pub fn process_remote_get_components_watching_request(
563    In(params): In<Option<Value>>,
564    world: &World,
565    mut removal_cursors: Local<HashMap<ComponentId, MessageCursor<RemovedComponentEntity>>>,
566) -> BrpResult<Option<Value>> {
567    let BrpGetComponentsParams {
568        entity,
569        components,
570        strict,
571    } = parse_some(params)?;
572
573    let app_type_registry = world.resource::<AppTypeRegistry>();
574    let type_registry = app_type_registry.read();
575    let entity_ref = get_entity(world, entity)?;
576
577    let mut changed = Vec::new();
578    let mut removed = Vec::new();
579    let mut errors = <HashMap<_, _>>::default();
580
581    'component_loop: for component_path in components {
582        let Ok(type_registration) =
583            get_component_type_registration(&type_registry, &component_path)
584        else {
585            let err =
586                BrpError::component_error(format!("Unknown component type: `{component_path}`"));
587            if strict {
588                return Err(err);
589            }
590            errors.insert(
591                component_path,
592                serde_json::to_value(err).map_err(BrpError::internal)?,
593            );
594            continue;
595        };
596        let Some(component_id) = world.components().get_valid_id(type_registration.type_id())
597        else {
598            let err = BrpError::component_error(format!("Unknown component: `{component_path}`"));
599            if strict {
600                return Err(err);
601            }
602            errors.insert(
603                component_path,
604                serde_json::to_value(err).map_err(BrpError::internal)?,
605            );
606            continue;
607        };
608
609        if let Some(ticks) = entity_ref.get_change_ticks_by_id(component_id)
610            && ticks.is_changed(world.last_change_tick(), world.read_change_tick())
611        {
612            changed.push(component_path);
613            continue;
614        };
615
616        let Some(events) = world.removed_components().get(component_id) else {
617            continue;
618        };
619        let cursor = removal_cursors
620            .entry(component_id)
621            .or_insert_with(|| events.get_cursor());
622        for event in cursor.read(events) {
623            if Entity::from(event.clone()) == entity {
624                removed.push(component_path);
625                continue 'component_loop;
626            }
627        }
628    }
629
630    if changed.is_empty() && removed.is_empty() {
631        return Ok(None);
632    }
633
634    let response =
635        reflect_components_to_response(changed, strict, entity, entity_ref, &type_registry)?;
636
637    let response = match response {
638        BrpGetComponentsResponse::Lenient {
639            components,
640            errors: mut errs,
641        } => BrpGetComponentsWatchingResponse::Lenient {
642            components,
643            removed,
644            errors: {
645                errs.extend(errors);
646                errs
647            },
648        },
649        BrpGetComponentsResponse::Strict(components) => BrpGetComponentsWatchingResponse::Strict {
650            components,
651            removed,
652        },
653    };
654
655    Ok(Some(
656        serde_json::to_value(response).map_err(BrpError::internal)?,
657    ))
658}
659
660/// Reflect a list of components on an entity into a [`BrpGetComponentsResponse`].
661fn reflect_components_to_response(
662    components: Vec<String>,
663    strict: bool,
664    entity: Entity,
665    entity_ref: EntityRef,
666    type_registry: &TypeRegistry,
667) -> BrpResult<BrpGetComponentsResponse> {
668    let mut response = if strict {
669        BrpGetComponentsResponse::Strict(Default::default())
670    } else {
671        BrpGetComponentsResponse::Lenient {
672            components: Default::default(),
673            errors: Default::default(),
674        }
675    };
676
677    for component_path in components {
678        match reflect_component(&component_path, entity, entity_ref, type_registry) {
679            Ok(serialized_object) => match response {
680                BrpGetComponentsResponse::Strict(ref mut components)
681                | BrpGetComponentsResponse::Lenient {
682                    ref mut components, ..
683                } => {
684                    components.extend(serialized_object.into_iter());
685                }
686            },
687            Err(err) => match response {
688                BrpGetComponentsResponse::Strict(_) => return Err(err),
689                BrpGetComponentsResponse::Lenient { ref mut errors, .. } => {
690                    let err_value = serde_json::to_value(err).map_err(BrpError::internal)?;
691                    errors.insert(component_path, err_value);
692                }
693            },
694        }
695    }
696
697    Ok(response)
698}
699
700/// Reflect a single component on an entity with the given component path.
701fn reflect_component(
702    component_path: &str,
703    entity: Entity,
704    entity_ref: EntityRef,
705    type_registry: &TypeRegistry,
706) -> BrpResult<Map<String, Value>> {
707    let reflect_component =
708        get_reflect_component(type_registry, component_path).map_err(BrpError::component_error)?;
709
710    // Retrieve the reflected value for the given specified component on the given entity.
711    let Some(reflected) = reflect_component.reflect(entity_ref) else {
712        return Err(BrpError::component_not_present(component_path, entity));
713    };
714
715    // Each component value serializes to a map with a single entry.
716    let reflect_serializer = ReflectSerializer::new(reflected.as_partial_reflect(), type_registry);
717    let Value::Object(serialized_object) =
718        serde_json::to_value(&reflect_serializer).map_err(BrpError::component_error)?
719    else {
720        return Err(BrpError {
721            code: error_codes::COMPONENT_ERROR,
722            message: format!("Component `{component_path}` could not be serialized"),
723            data: None,
724        });
725    };
726
727    Ok(serialized_object)
728}
729
730/// A selector for components in a query.
731///
732/// This can either be a list of component paths or an "all" selector that
733/// indicates that all components should be selected.
734/// The "all" selector is useful when you want to retrieve all components
735/// present on an entity without specifying each one individually.
736/// The paths in the `Paths` variant must be the [full type paths]: e.g.
737/// `bevy_transform::components::transform::Transform`, not just
738/// `Transform`.
739///
740#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
741#[serde(rename_all = "snake_case")]
742pub enum ComponentSelector {
743    /// An "all" selector that indicates all components should be selected.
744    All,
745    /// A list of component paths to select as optional components.
746    #[serde(untagged)]
747    Paths(Vec<String>),
748}
749
750impl Default for ComponentSelector {
751    fn default() -> Self {
752        Self::Paths(Vec::default())
753    }
754}
755
756/// Handles a `world.query` request coming from a client.
757pub fn process_remote_query_request(In(params): In<Option<Value>>, world: &mut World) -> BrpResult {
758    let BrpQueryParams {
759        data: BrpQuery {
760            components,
761            option,
762            has,
763        },
764        filter,
765        strict,
766    } = match params {
767        Some(params) => parse_some(Some(params))?,
768        None => BrpQueryParams {
769            data: BrpQuery {
770                components: Vec::new(),
771                option: ComponentSelector::default(),
772                has: Vec::new(),
773            },
774            filter: BrpQueryFilter::default(),
775            strict: false,
776        },
777    };
778
779    let app_type_registry = world.resource::<AppTypeRegistry>().clone();
780    let type_registry = app_type_registry.read();
781
782    // Required components: must be present
783    let (required, unregistered_in_required) =
784        get_component_ids(&type_registry, world, components.clone(), strict)
785            .map_err(BrpError::component_error)?;
786
787    // Optional components: Option<&T> or all reflectable if "all"
788    let (optional, _) = match &option {
789        ComponentSelector::Paths(paths) => {
790            get_component_ids(&type_registry, world, paths.clone(), strict)
791                .map_err(BrpError::component_error)?
792        }
793        ComponentSelector::All => (Vec::new(), Vec::new()),
794    };
795
796    // Has components: presence check
797    let (has_ids, unregistered_in_has) =
798        get_component_ids(&type_registry, world, has, strict).map_err(BrpError::component_error)?;
799
800    // Filters
801    let (without, _) = get_component_ids(&type_registry, world, filter.without.clone(), strict)
802        .map_err(BrpError::component_error)?;
803    let (with, unregistered_in_with) =
804        get_component_ids(&type_registry, world, filter.with.clone(), strict)
805            .map_err(BrpError::component_error)?;
806
807    // When "strict" is false:
808    // - Unregistered components in "option" and "without" are ignored.
809    // - Unregistered components in "has" are considered absent from the entity.
810    // - Unregistered components in "components" and "with" result in an empty
811    // response since they specify hard requirements.
812    // If strict, fail if any required or with components are unregistered
813    if !unregistered_in_required.is_empty() || !unregistered_in_with.is_empty() {
814        return serde_json::to_value(BrpQueryResponse::default()).map_err(BrpError::internal);
815    }
816
817    let mut query = QueryBuilder::<FilteredEntityRef>::new(world);
818    for (_, component) in &required {
819        query.ref_id(*component);
820    }
821    for (_, option) in &optional {
822        query.optional(|query| {
823            query.ref_id(*option);
824        });
825    }
826    for (_, has) in &has_ids {
827        query.optional(|query| {
828            query.ref_id(*has);
829        });
830    }
831    for (_, without) in without {
832        query.without_id(without);
833    }
834    for (_, with) in with {
835        query.with_id(with);
836    }
837
838    // Prepare has reflect info
839    let has_paths_and_reflect_components: Vec<(&str, &ReflectComponent)> = has_ids
840        .iter()
841        .map(|(type_id, _)| reflect_component_from_id(*type_id, &type_registry))
842        .collect::<AnyhowResult<Vec<(&str, &ReflectComponent)>>>()
843        .map_err(BrpError::component_error)?;
844
845    let mut response = BrpQueryResponse::default();
846    let mut query = query.build();
847
848    for row in query.iter(world) {
849        let entity_id = row.id();
850        let entity_ref = world.get_entity(entity_id).expect("Entity should exist");
851
852        // Required components
853        let mut components_map = serialize_components(
854            entity_ref,
855            &type_registry,
856            required
857                .iter()
858                .map(|(type_id, component_id)| (*type_id, Some(*component_id))),
859        );
860
861        // Optional components
862        match &option {
863            ComponentSelector::All => {
864                // Add all reflectable components present on the entity (as Option<&T>)
865                let all_optionals =
866                    entity_ref
867                        .archetype()
868                        .components()
869                        .iter()
870                        .filter_map(|&component_id| {
871                            let info = world.components().get_info(component_id)?;
872                            let type_id = info.type_id()?;
873                            // Skip required components (already included)
874                            if required.iter().any(|(_, cid)| cid == &component_id) {
875                                return None;
876                            }
877                            Some((type_id, Some(component_id)))
878                        });
879                components_map.extend(serialize_components(
880                    entity_ref,
881                    &type_registry,
882                    all_optionals,
883                ));
884            }
885            ComponentSelector::Paths(_) => {
886                // Add only the requested optional components (as Option<&T>)
887                let optionals = optional.iter().filter(|(_, component_id)| {
888                    // Skip required components (already included)
889                    !required.iter().any(|(_, cid)| cid == component_id)
890                });
891                components_map.extend(serialize_components(
892                    entity_ref,
893                    &type_registry,
894                    optionals
895                        .clone()
896                        .map(|(type_id, component_id)| (*type_id, Some(*component_id))),
897                ));
898            }
899        }
900
901        // The map of boolean-valued component presences:
902        let has_map = build_has_map(
903            row,
904            has_paths_and_reflect_components.iter().copied(),
905            &unregistered_in_has,
906        );
907
908        let query_row = BrpQueryRow {
909            entity: row.id(),
910            components: components_map,
911            has: has_map,
912        };
913
914        response.push(query_row);
915    }
916
917    serde_json::to_value(response).map_err(BrpError::internal)
918}
919
920/// Serializes the specified components for an entity.
921/// The iterator yields ([`TypeId`], Option<[`ComponentId`]>).
922fn serialize_components(
923    entity_ref: EntityRef,
924    type_registry: &TypeRegistry,
925    components: impl Iterator<Item = (TypeId, Option<ComponentId>)>,
926) -> HashMap<String, Value> {
927    let mut components_map = HashMap::new();
928    for (type_id, component_id_opt) in components {
929        let Some(type_registration) = type_registry.get(type_id) else {
930            continue;
931        };
932        if let Some(reflect_component) = type_registration.data::<ReflectComponent>() {
933            // If a component_id is provided, check if the entity has it
934            if let Some(component_id) = component_id_opt
935                && !entity_ref.contains_id(component_id)
936            {
937                continue;
938            }
939            if let Some(reflected) = reflect_component.reflect(entity_ref) {
940                let reflect_serializer =
941                    ReflectSerializer::new(reflected.as_partial_reflect(), type_registry);
942                if let Ok(Value::Object(obj)) = serde_json::to_value(&reflect_serializer) {
943                    components_map.extend(obj);
944                } else {
945                    warn_once!(
946                        "Failed to serialize component `{}` for entity {:?}",
947                        type_registration.type_info().type_path(),
948                        entity_ref.id()
949                    );
950                }
951            }
952        }
953    }
954    components_map
955}
956
957/// Handles a `world.spawn_entity` request coming from a client.
958pub fn process_remote_spawn_entity_request(
959    In(params): In<Option<Value>>,
960    world: &mut World,
961) -> BrpResult {
962    let BrpSpawnEntityParams { components } = parse_some(params)?;
963
964    let app_type_registry = world.resource::<AppTypeRegistry>().clone();
965    let type_registry = app_type_registry.read();
966
967    let reflect_components =
968        deserialize_components(&type_registry, components).map_err(BrpError::component_error)?;
969
970    let entity = world.spawn_empty();
971    let entity_id = entity.id();
972    insert_reflected_components(entity, reflect_components).map_err(BrpError::component_error)?;
973
974    let response = BrpSpawnEntityResponse { entity: entity_id };
975    serde_json::to_value(response).map_err(BrpError::internal)
976}
977
978/// Handles a `rpc.discover` request coming from a client.
979pub fn process_remote_list_methods_request(
980    In(_params): In<Option<Value>>,
981    world: &mut World,
982) -> BrpResult {
983    let remote_methods = world.resource::<crate::RemoteMethods>();
984
985    #[cfg(all(feature = "http", not(target_family = "wasm")))]
986    let servers = match (
987        world.get_resource::<crate::http::HostAddress>(),
988        world.get_resource::<crate::http::HostPort>(),
989    ) {
990        (Some(url), Some(port)) => Some(vec![ServerObject {
991            name: "Server".to_owned(),
992            url: format!("{}:{}", url.0, port.0),
993            ..default()
994        }]),
995        (Some(url), None) => Some(vec![ServerObject {
996            name: "Server".to_owned(),
997            url: url.0.to_string(),
998            ..default()
999        }]),
1000        _ => None,
1001    };
1002
1003    #[cfg(any(not(feature = "http"), target_family = "wasm"))]
1004    let servers = None;
1005
1006    let doc = OpenRpcDocument {
1007        info: Default::default(),
1008        methods: remote_methods.into(),
1009        openrpc: "1.3.2".to_owned(),
1010        servers,
1011    };
1012
1013    serde_json::to_value(doc).map_err(BrpError::internal)
1014}
1015
1016/// Handles a `world.insert_components` request (insert components) coming from a client.
1017pub fn process_remote_insert_components_request(
1018    In(params): In<Option<Value>>,
1019    world: &mut World,
1020) -> BrpResult {
1021    let BrpInsertComponentsParams { entity, components } = parse_some(params)?;
1022
1023    let app_type_registry = world.resource::<AppTypeRegistry>().clone();
1024    let type_registry = app_type_registry.read();
1025
1026    let reflect_components =
1027        deserialize_components(&type_registry, components).map_err(BrpError::component_error)?;
1028
1029    insert_reflected_components(get_entity_mut(world, entity)?, reflect_components)
1030        .map_err(BrpError::component_error)?;
1031
1032    Ok(Value::Null)
1033}
1034
1035/// Handles a `world.insert_resources` request coming from a client.
1036pub fn process_remote_insert_resources_request(
1037    In(params): In<Option<Value>>,
1038    world: &mut World,
1039) -> BrpResult {
1040    let BrpInsertResourcesParams {
1041        resource: resource_path,
1042        value,
1043    } = parse_some(params)?;
1044
1045    let app_type_registry = world.resource::<AppTypeRegistry>().clone();
1046    let type_registry = app_type_registry.read();
1047
1048    let reflected_resource = deserialize_resource(&type_registry, &resource_path, value)
1049        .map_err(BrpError::resource_error)?;
1050
1051    let reflect_resource =
1052        get_reflect_resource(&type_registry, &resource_path).map_err(BrpError::resource_error)?;
1053    reflect_resource.insert(world, &*reflected_resource, &type_registry);
1054
1055    Ok(Value::Null)
1056}
1057
1058/// Handles a `world.mutate_components` request coming from a client.
1059///
1060/// This method allows you to mutate a single field inside an Entity's
1061/// component.
1062pub fn process_remote_mutate_components_request(
1063    In(params): In<Option<Value>>,
1064    world: &mut World,
1065) -> BrpResult {
1066    let BrpMutateComponentsParams {
1067        entity,
1068        component,
1069        path,
1070        value,
1071    } = parse_some(params)?;
1072    let app_type_registry = world.resource::<AppTypeRegistry>().clone();
1073    let type_registry = app_type_registry.read();
1074
1075    // Get the fully-qualified type names of the component to be mutated.
1076    let component_type: &TypeRegistration = type_registry
1077        .get_with_type_path(&component)
1078        .ok_or_else(|| {
1079            BrpError::component_error(anyhow!("Unknown component type: `{}`", component))
1080        })?;
1081
1082    // Get the reflected representation of the component.
1083    let mut reflected = component_type
1084        .data::<ReflectComponent>()
1085        .ok_or_else(|| {
1086            BrpError::component_error(anyhow!("Component `{}` isn't registered", component))
1087        })?
1088        .reflect_mut(world.entity_mut(entity))
1089        .ok_or_else(|| {
1090            BrpError::component_error(anyhow!("Cannot reflect component `{}`", component))
1091        })?;
1092
1093    // Get the type of the field in the component that is to be
1094    // mutated.
1095    let value_type: &TypeRegistration = type_registry
1096        .get_with_type_path(
1097            reflected
1098                .reflect_path(path.as_str())
1099                .map_err(BrpError::component_error)?
1100                .reflect_type_path(),
1101        )
1102        .ok_or_else(|| {
1103            BrpError::component_error(anyhow!("Unknown component field type: `{}`", component))
1104        })?;
1105
1106    // Get the reflected representation of the value to be inserted
1107    // into the component.
1108    let value: Box<dyn PartialReflect> = TypedReflectDeserializer::new(value_type, &type_registry)
1109        .deserialize(&value)
1110        .map_err(BrpError::component_error)?;
1111
1112    // Apply the mutation.
1113    reflected
1114        .reflect_path_mut(path.as_str())
1115        .map_err(BrpError::component_error)?
1116        .try_apply(value.as_ref())
1117        .map_err(BrpError::component_error)?;
1118
1119    Ok(Value::Null)
1120}
1121
1122/// Handles a `world.mutate_resources` request coming from a client.
1123pub fn process_remote_mutate_resources_request(
1124    In(params): In<Option<Value>>,
1125    world: &mut World,
1126) -> BrpResult {
1127    let BrpMutateResourcesParams {
1128        resource: resource_path,
1129        path: field_path,
1130        value,
1131    } = parse_some(params)?;
1132
1133    let app_type_registry = world.resource::<AppTypeRegistry>().clone();
1134    let type_registry = app_type_registry.read();
1135
1136    // Get the `ReflectResource` for the given resource path.
1137    let reflect_resource =
1138        get_reflect_resource(&type_registry, &resource_path).map_err(BrpError::resource_error)?;
1139
1140    // Get the actual resource value from the world as a `dyn Reflect`.
1141    let mut reflected_resource = reflect_resource
1142        .reflect_mut(world)
1143        .map_err(|_| BrpError::resource_not_present(&resource_path))?;
1144
1145    // Get the type registration for the field with the given path.
1146    let value_registration = type_registry
1147        .get_with_type_path(
1148            reflected_resource
1149                .reflect_path(field_path.as_str())
1150                .map_err(BrpError::resource_error)?
1151                .reflect_type_path(),
1152        )
1153        .ok_or_else(|| {
1154            BrpError::resource_error(anyhow!("Unknown resource field type: `{}`", resource_path))
1155        })?;
1156
1157    // Use the field's type registration to deserialize the given value.
1158    let deserialized_value: Box<dyn PartialReflect> =
1159        TypedReflectDeserializer::new(value_registration, &type_registry)
1160            .deserialize(&value)
1161            .map_err(BrpError::resource_error)?;
1162
1163    // Apply the value to the resource.
1164    reflected_resource
1165        .reflect_path_mut(field_path.as_str())
1166        .map_err(BrpError::resource_error)?
1167        .try_apply(&*deserialized_value)
1168        .map_err(BrpError::resource_error)?;
1169
1170    Ok(Value::Null)
1171}
1172
1173/// Handles a `world.remove_components` request (remove components) coming from a client.
1174pub fn process_remote_remove_components_request(
1175    In(params): In<Option<Value>>,
1176    world: &mut World,
1177) -> BrpResult {
1178    let BrpRemoveComponentsParams { entity, components } = parse_some(params)?;
1179
1180    let app_type_registry = world.resource::<AppTypeRegistry>().clone();
1181    let type_registry = app_type_registry.read();
1182
1183    let component_ids = get_component_ids(&type_registry, world, components, true)
1184        .and_then(|(registered, unregistered)| {
1185            if unregistered.is_empty() {
1186                Ok(registered)
1187            } else {
1188                Err(anyhow!("Unregistered component types: {:?}", unregistered))
1189            }
1190        })
1191        .map_err(BrpError::component_error)?;
1192
1193    // Remove the components.
1194    let mut entity_world_mut = get_entity_mut(world, entity)?;
1195    for (_, component_id) in component_ids.iter() {
1196        entity_world_mut.remove_by_id(*component_id);
1197    }
1198
1199    Ok(Value::Null)
1200}
1201
1202/// Handles a `world.remove_resources` request coming from a client.
1203pub fn process_remote_remove_resources_request(
1204    In(params): In<Option<Value>>,
1205    world: &mut World,
1206) -> BrpResult {
1207    let BrpRemoveResourcesParams {
1208        resource: resource_path,
1209    } = parse_some(params)?;
1210
1211    let app_type_registry = world.resource::<AppTypeRegistry>().clone();
1212    let type_registry = app_type_registry.read();
1213
1214    let reflect_resource =
1215        get_reflect_resource(&type_registry, &resource_path).map_err(BrpError::resource_error)?;
1216    reflect_resource.remove(world);
1217
1218    Ok(Value::Null)
1219}
1220
1221/// Handles a `world.despawn_entity` (despawn entity) request coming from a client.
1222pub fn process_remote_despawn_entity_request(
1223    In(params): In<Option<Value>>,
1224    world: &mut World,
1225) -> BrpResult {
1226    let BrpDespawnEntityParams { entity } = parse_some(params)?;
1227
1228    get_entity_mut(world, entity)?.despawn();
1229
1230    Ok(Value::Null)
1231}
1232
1233/// Handles a `world.reparent_entities` request coming from a client.
1234pub fn process_remote_reparent_entities_request(
1235    In(params): In<Option<Value>>,
1236    world: &mut World,
1237) -> BrpResult {
1238    let BrpReparentEntitiesParams {
1239        entities,
1240        parent: maybe_parent,
1241    } = parse_some(params)?;
1242
1243    // If `Some`, reparent the entities.
1244    if let Some(parent) = maybe_parent {
1245        let mut parent_commands =
1246            get_entity_mut(world, parent).map_err(|_| BrpError::entity_not_found(parent))?;
1247        for entity in entities {
1248            if entity == parent {
1249                return Err(BrpError::self_reparent(entity));
1250            }
1251            parent_commands.add_child(entity);
1252        }
1253    }
1254    // If `None`, remove the entities' parents.
1255    else {
1256        for entity in entities {
1257            get_entity_mut(world, entity)?.remove::<ChildOf>();
1258        }
1259    }
1260
1261    Ok(Value::Null)
1262}
1263
1264/// Handles a `world.list_components` request (list all components) coming from a client.
1265pub fn process_remote_list_components_request(
1266    In(params): In<Option<Value>>,
1267    world: &World,
1268) -> BrpResult {
1269    let app_type_registry = world.resource::<AppTypeRegistry>();
1270    let type_registry = app_type_registry.read();
1271
1272    let mut response = BrpListComponentsResponse::default();
1273
1274    // If `Some`, return all components of the provided entity.
1275    if let Some(BrpListComponentsParams { entity }) = params.map(parse).transpose()? {
1276        let entity = get_entity(world, entity)?;
1277        for &component_id in entity.archetype().components().iter() {
1278            let Some(component_info) = world.components().get_info(component_id) else {
1279                continue;
1280            };
1281            response.push(component_info.name().to_string());
1282        }
1283    }
1284    // If `None`, list all registered components.
1285    else {
1286        for registered_type in type_registry.iter() {
1287            if registered_type.data::<ReflectComponent>().is_some() {
1288                response.push(registered_type.type_info().type_path().to_owned());
1289            }
1290        }
1291    }
1292
1293    // Sort both for cleanliness and to reduce the risk that clients start
1294    // accidentally depending on the order.
1295    response.sort();
1296
1297    serde_json::to_value(response).map_err(BrpError::internal)
1298}
1299
1300/// Handles a `world.list_resources` request coming from a client.
1301pub fn process_remote_list_resources_request(
1302    In(_params): In<Option<Value>>,
1303    world: &World,
1304) -> BrpResult {
1305    let mut response = BrpListResourcesResponse::default();
1306
1307    let app_type_registry = world.resource::<AppTypeRegistry>();
1308    let type_registry = app_type_registry.read();
1309
1310    for registered_type in type_registry.iter() {
1311        if registered_type.data::<ReflectResource>().is_some() {
1312            response.push(registered_type.type_info().type_path().to_owned());
1313        }
1314    }
1315
1316    response.sort();
1317
1318    serde_json::to_value(response).map_err(BrpError::internal)
1319}
1320
1321/// Handles a `world.list_components+watch` request coming from a client.
1322pub fn process_remote_list_components_watching_request(
1323    In(params): In<Option<Value>>,
1324    world: &World,
1325    mut removal_cursors: Local<HashMap<ComponentId, MessageCursor<RemovedComponentEntity>>>,
1326) -> BrpResult<Option<Value>> {
1327    let BrpListComponentsParams { entity } = parse_some(params)?;
1328    let entity_ref = get_entity(world, entity)?;
1329    let mut response = BrpListComponentsWatchingResponse::default();
1330
1331    for &component_id in entity_ref.archetype().components().iter() {
1332        let ticks = entity_ref
1333            .get_change_ticks_by_id(component_id)
1334            .ok_or(BrpError::internal("Failed to get ticks"))?;
1335
1336        if ticks.is_added(world.last_change_tick(), world.read_change_tick()) {
1337            let Some(component_info) = world.components().get_info(component_id) else {
1338                continue;
1339            };
1340            response.added.push(component_info.name().to_string());
1341        }
1342    }
1343
1344    for (component_id, events) in world.removed_components().iter() {
1345        let cursor = removal_cursors
1346            .entry(*component_id)
1347            .or_insert_with(|| events.get_cursor());
1348        for event in cursor.read(events) {
1349            if Entity::from(event.clone()) == entity {
1350                let Some(component_info) = world.components().get_info(*component_id) else {
1351                    continue;
1352                };
1353                response.removed.push(component_info.name().to_string());
1354            }
1355        }
1356    }
1357
1358    if response.added.is_empty() && response.removed.is_empty() {
1359        Ok(None)
1360    } else {
1361        Ok(Some(
1362            serde_json::to_value(response).map_err(BrpError::internal)?,
1363        ))
1364    }
1365}
1366
1367/// Handles a `world.trigger_event` request coming from a client.
1368pub fn process_remote_trigger_event_request(
1369    In(params): In<Option<Value>>,
1370    world: &mut World,
1371) -> BrpResult {
1372    let BrpTriggerEventParams { event, value } = parse_some(params)?;
1373
1374    world.resource_scope(|world, registry: Mut<AppTypeRegistry>| {
1375        let registry = registry.read();
1376
1377        let Some(registration) = registry.get_with_type_path(&event) else {
1378            return Err(BrpError::resource_error(format!(
1379                "Unknown event type: `{event}`"
1380            )));
1381        };
1382        let Some(reflect_event) = registration.data::<ReflectEvent>() else {
1383            return Err(BrpError::resource_error(format!(
1384                "Event `{event}` is not reflectable"
1385            )));
1386        };
1387
1388        if let Some(payload) = value {
1389            let payload: Box<dyn PartialReflect> =
1390                TypedReflectDeserializer::new(registration, &registry)
1391                    .deserialize(payload.into_deserializer())
1392                    .map_err(|err| {
1393                        BrpError::resource_error(format!("{event} is invalid: {err}"))
1394                    })?;
1395            reflect_event.trigger(world, &*payload, &registry);
1396        } else {
1397            let payload = DynamicStruct::default();
1398            reflect_event.trigger(world, &payload, &registry);
1399        }
1400
1401        Ok(Value::Null)
1402    })
1403}
1404
1405/// Handles a `registry.schema` request (list all registry types in form of schema) coming from a client.
1406pub fn export_registry_types(In(params): In<Option<Value>>, world: &World) -> BrpResult {
1407    let filter: BrpJsonSchemaQueryFilter = match params {
1408        None => Default::default(),
1409        Some(params) => parse(params)?,
1410    };
1411
1412    let extra_info = world.resource::<crate::schemas::SchemaTypesMetadata>();
1413    let types = world.resource::<AppTypeRegistry>();
1414    let types = types.read();
1415    let schemas = types
1416        .iter()
1417        .filter_map(|type_reg| {
1418            let path_table = type_reg.type_info().type_path_table();
1419            if let Some(crate_name) = &path_table.crate_name() {
1420                if !filter.with_crates.is_empty()
1421                    && !filter.with_crates.iter().any(|c| crate_name.eq(c))
1422                {
1423                    return None;
1424                }
1425                if !filter.without_crates.is_empty()
1426                    && filter.without_crates.iter().any(|c| crate_name.eq(c))
1427                {
1428                    return None;
1429                }
1430            }
1431            let (id, schema) = export_type(type_reg, extra_info);
1432
1433            if !filter.type_limit.with.is_empty()
1434                && !filter
1435                    .type_limit
1436                    .with
1437                    .iter()
1438                    .any(|c| schema.reflect_types.iter().any(|cc| c.eq(cc)))
1439            {
1440                return None;
1441            }
1442            if !filter.type_limit.without.is_empty()
1443                && filter
1444                    .type_limit
1445                    .without
1446                    .iter()
1447                    .any(|c| schema.reflect_types.iter().any(|cc| c.eq(cc)))
1448            {
1449                return None;
1450            }
1451            Some((id.to_string(), schema))
1452        })
1453        .collect::<HashMap<String, JsonSchemaBevyType>>();
1454
1455    serde_json::to_value(schemas).map_err(BrpError::internal)
1456}
1457
1458/// Immutably retrieves an entity from the [`World`], returning an error if the
1459/// entity isn't present.
1460fn get_entity(world: &World, entity: Entity) -> Result<EntityRef<'_>, BrpError> {
1461    world
1462        .get_entity(entity)
1463        .map_err(|_| BrpError::entity_not_found(entity))
1464}
1465
1466/// Mutably retrieves an entity from the [`World`], returning an error if the
1467/// entity isn't present.
1468fn get_entity_mut(world: &mut World, entity: Entity) -> Result<EntityWorldMut<'_>, BrpError> {
1469    world
1470        .get_entity_mut(entity)
1471        .map_err(|_| BrpError::entity_not_found(entity))
1472}
1473
1474/// Given components full path, returns a tuple that contains
1475/// - A list of corresponding [`TypeId`] and [`ComponentId`] for registered components.
1476/// - A list of unregistered component paths.
1477///
1478/// Note that the supplied path names must be *full* path names: e.g.
1479/// `bevy_transform::components::transform::Transform` instead of `Transform`.
1480fn get_component_ids(
1481    type_registry: &TypeRegistry,
1482    world: &World,
1483    component_paths: Vec<String>,
1484    strict: bool,
1485) -> AnyhowResult<(Vec<(TypeId, ComponentId)>, Vec<String>)> {
1486    let mut component_ids = vec![];
1487    let mut unregistered_components = vec![];
1488
1489    for component_path in component_paths {
1490        let maybe_component_tuple = get_component_type_registration(type_registry, &component_path)
1491            .ok()
1492            .and_then(|type_registration| {
1493                let type_id = type_registration.type_id();
1494                world
1495                    .components()
1496                    .get_valid_id(type_id)
1497                    .map(|component_id| (type_id, component_id))
1498            });
1499        if let Some((type_id, component_id)) = maybe_component_tuple {
1500            component_ids.push((type_id, component_id));
1501        } else if strict {
1502            return Err(anyhow!(
1503                "Component `{}` isn't registered or used in the world",
1504                component_path
1505            ));
1506        } else {
1507            unregistered_components.push(component_path);
1508        }
1509    }
1510
1511    Ok((component_ids, unregistered_components))
1512}
1513
1514/// Given an entity (`entity_ref`),
1515/// a list of reflected component information (`paths_and_reflect_components`)
1516/// and a list of unregistered components,
1517/// return a map which associates each component to a boolean value indicating
1518/// whether or not that component is present on the entity.
1519/// Unregistered components are considered absent from the entity.
1520fn build_has_map<'a>(
1521    entity_ref: FilteredEntityRef,
1522    paths_and_reflect_components: impl Iterator<Item = (&'a str, &'a ReflectComponent)>,
1523    unregistered_components: &[String],
1524) -> HashMap<String, Value> {
1525    let mut has_map = <HashMap<_, _>>::default();
1526
1527    for (type_path, reflect_component) in paths_and_reflect_components {
1528        let has = reflect_component.contains(entity_ref);
1529        has_map.insert(type_path.to_owned(), Value::Bool(has));
1530    }
1531    unregistered_components.iter().for_each(|component| {
1532        has_map.insert(component.to_owned(), Value::Bool(false));
1533    });
1534
1535    has_map
1536}
1537
1538/// Given a component ID, return the associated [type path] and `ReflectComponent` if possible.
1539///
1540/// The `ReflectComponent` part is the meat of this; the type path is only used for error messages.
1541///
1542/// [type path]: bevy_reflect::TypePath::type_path
1543fn reflect_component_from_id(
1544    component_type_id: TypeId,
1545    type_registry: &TypeRegistry,
1546) -> AnyhowResult<(&str, &ReflectComponent)> {
1547    let Some(type_registration) = type_registry.get(component_type_id) else {
1548        return Err(anyhow!(
1549            "Component `{:?}` isn't registered",
1550            component_type_id
1551        ));
1552    };
1553
1554    let type_path = type_registration.type_info().type_path();
1555
1556    let Some(reflect_component) = type_registration.data::<ReflectComponent>() else {
1557        return Err(anyhow!("Component `{}` isn't reflectable", type_path));
1558    };
1559
1560    Ok((type_path, reflect_component))
1561}
1562
1563/// Given a collection of component paths and their associated serialized values (`components`),
1564/// return the associated collection of deserialized reflected values.
1565fn deserialize_components(
1566    type_registry: &TypeRegistry,
1567    components: HashMap<String, Value>,
1568) -> AnyhowResult<Vec<Box<dyn PartialReflect>>> {
1569    let mut reflect_components = vec![];
1570
1571    for (component_path, component) in components {
1572        let Some(component_type) = type_registry.get_with_type_path(&component_path) else {
1573            return Err(anyhow!("Unknown component type: `{}`", component_path));
1574        };
1575        let reflected: Box<dyn PartialReflect> =
1576            TypedReflectDeserializer::new(component_type, type_registry)
1577                .deserialize(&component)
1578                .map_err(|err| anyhow!("{component_path} is invalid: {err}"))?;
1579        reflect_components.push(reflected);
1580    }
1581
1582    Ok(reflect_components)
1583}
1584
1585/// Given a resource path and an associated serialized value (`value`), return the
1586/// deserialized value.
1587fn deserialize_resource(
1588    type_registry: &TypeRegistry,
1589    resource_path: &str,
1590    value: Value,
1591) -> AnyhowResult<Box<dyn PartialReflect>> {
1592    let Some(resource_type) = type_registry.get_with_type_path(resource_path) else {
1593        return Err(anyhow!("Unknown resource type: `{}`", resource_path));
1594    };
1595    let reflected: Box<dyn PartialReflect> =
1596        TypedReflectDeserializer::new(resource_type, type_registry)
1597            .deserialize(&value)
1598            .map_err(|err| anyhow!("{resource_path} is invalid: {err}"))?;
1599    Ok(reflected)
1600}
1601
1602/// Given a collection `reflect_components` of reflected component values, insert them into
1603/// the given entity (`entity_world_mut`).
1604fn insert_reflected_components(
1605    mut entity_world_mut: EntityWorldMut,
1606    reflect_components: Vec<Box<dyn PartialReflect>>,
1607) -> AnyhowResult<()> {
1608    for reflected in reflect_components {
1609        entity_world_mut.insert_reflect(reflected);
1610    }
1611
1612    Ok(())
1613}
1614
1615/// Given a component's type path, return the associated [`ReflectComponent`] from the given
1616/// `type_registry` if possible.
1617fn get_reflect_component<'r>(
1618    type_registry: &'r TypeRegistry,
1619    component_path: &str,
1620) -> AnyhowResult<&'r ReflectComponent> {
1621    let component_registration = get_component_type_registration(type_registry, component_path)?;
1622
1623    component_registration
1624        .data::<ReflectComponent>()
1625        .ok_or_else(|| anyhow!("Component `{}` isn't reflectable", component_path))
1626}
1627
1628/// Given a component's type path, return the associated [`TypeRegistration`] from the given
1629/// `type_registry` if possible.
1630fn get_component_type_registration<'r>(
1631    type_registry: &'r TypeRegistry,
1632    component_path: &str,
1633) -> AnyhowResult<&'r TypeRegistration> {
1634    type_registry
1635        .get_with_type_path(component_path)
1636        .ok_or_else(|| anyhow!("Unknown component type: `{}`", component_path))
1637}
1638
1639/// Given a resource's type path, return the associated [`ReflectResource`] from the given
1640/// `type_registry` if possible.
1641fn get_reflect_resource<'r>(
1642    type_registry: &'r TypeRegistry,
1643    resource_path: &str,
1644) -> AnyhowResult<&'r ReflectResource> {
1645    let resource_registration = get_resource_type_registration(type_registry, resource_path)?;
1646
1647    resource_registration
1648        .data::<ReflectResource>()
1649        .ok_or_else(|| anyhow!("Resource `{}` isn't reflectable", resource_path))
1650}
1651
1652/// Given a resource's type path, return the associated [`TypeRegistration`] from the given
1653/// `type_registry` if possible.
1654fn get_resource_type_registration<'r>(
1655    type_registry: &'r TypeRegistry,
1656    resource_path: &str,
1657) -> AnyhowResult<&'r TypeRegistration> {
1658    type_registry
1659        .get_with_type_path(resource_path)
1660        .ok_or_else(|| anyhow!("Unknown resource type: `{}`", resource_path))
1661}
1662
1663#[cfg(test)]
1664mod tests {
1665    /// A generic function that tests serialization and deserialization of any type
1666    /// implementing Serialize and Deserialize traits.
1667    fn test_serialize_deserialize<T>(value: T)
1668    where
1669        T: Serialize + for<'a> Deserialize<'a> + PartialEq + core::fmt::Debug,
1670    {
1671        // Serialize the value to JSON string
1672        let serialized = serde_json::to_string(&value).expect("Failed to serialize");
1673
1674        // Deserialize the JSON string back into the original type
1675        let deserialized: T = serde_json::from_str(&serialized).expect("Failed to deserialize");
1676
1677        // Assert that the deserialized value is the same as the original
1678        assert_eq!(
1679            &value, &deserialized,
1680            "Deserialized value does not match original"
1681        );
1682    }
1683
1684    use super::*;
1685    use bevy_ecs::{
1686        component::Component, event::Event, observer::On, resource::Resource, system::ResMut,
1687    };
1688    use bevy_reflect::Reflect;
1689    use serde_json::Value::Null;
1690
1691    #[test]
1692    fn insert_reflect_only_component() {
1693        #[derive(Reflect, Component)]
1694        #[reflect(Component)]
1695        struct Player {
1696            name: String,
1697            health: u32,
1698        }
1699        let components: HashMap<String, Value> = [(
1700            String::from("bevy_remote::builtin_methods::tests::Player"),
1701            serde_json::json!({"name": "John", "health": 50}),
1702        )]
1703        .into();
1704        let atr = AppTypeRegistry::default();
1705        {
1706            let mut register = atr.write();
1707            register.register::<Player>();
1708        }
1709        let deserialized_components = {
1710            let type_reg = atr.read();
1711            deserialize_components(&type_reg, components).expect("FAIL")
1712        };
1713        let mut world = World::new();
1714        world.insert_resource(atr);
1715        let e = world.spawn_empty();
1716        insert_reflected_components(e, deserialized_components).expect("FAIL");
1717    }
1718
1719    #[test]
1720    fn trigger_reflect_only_event() {
1721        #[derive(Event, Reflect)]
1722        #[reflect(Event)]
1723        struct Pass;
1724
1725        #[derive(Resource)]
1726        struct TestResult(pub bool);
1727
1728        let atr = AppTypeRegistry::default();
1729        {
1730            let mut register = atr.write();
1731            register.register::<Pass>();
1732        }
1733        let mut world = World::new();
1734        world.add_observer(move |_event: On<Pass>, mut result: ResMut<TestResult>| result.0 = true);
1735        world.insert_resource(TestResult(false));
1736        world.insert_resource(atr);
1737
1738        let params = serde_json::to_value(&BrpTriggerEventParams {
1739            event: "bevy_remote::builtin_methods::tests::Pass".to_owned(),
1740            value: None,
1741        })
1742        .expect("FAIL");
1743        assert_eq!(
1744            process_remote_trigger_event_request(In(Some(params)), &mut world),
1745            Ok(Null)
1746        );
1747        assert!(world.resource::<TestResult>().0);
1748    }
1749
1750    #[test]
1751    fn serialization_tests() {
1752        test_serialize_deserialize(BrpQueryRow {
1753            components: Default::default(),
1754            entity: Entity::from_raw_u32(0).unwrap(),
1755            has: Default::default(),
1756        });
1757        test_serialize_deserialize(BrpListComponentsWatchingResponse::default());
1758        test_serialize_deserialize(BrpQuery::default());
1759        test_serialize_deserialize(BrpJsonSchemaQueryFilter::default());
1760        test_serialize_deserialize(BrpJsonSchemaQueryFilter {
1761            type_limit: JsonSchemaTypeLimit {
1762                with: vec!["Resource".to_owned()],
1763                ..Default::default()
1764            },
1765            ..Default::default()
1766        });
1767        test_serialize_deserialize(BrpListComponentsParams {
1768            entity: Entity::from_raw_u32(0).unwrap(),
1769        });
1770    }
1771}