1use 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
38pub const BRP_GET_COMPONENTS_METHOD: &str = "world.get_components";
40
41pub const BRP_QUERY_METHOD: &str = "world.query";
43
44pub const BRP_SPAWN_ENTITY_METHOD: &str = "world.spawn_entity";
46
47pub const BRP_INSERT_COMPONENTS_METHOD: &str = "world.insert_components";
49
50pub const BRP_REMOVE_COMPONENTS_METHOD: &str = "world.remove_components";
52
53pub const BRP_DESPAWN_COMPONENTS_METHOD: &str = "world.despawn_entity";
55
56pub const BRP_REPARENT_ENTITIES_METHOD: &str = "world.reparent_entities";
58
59pub const BRP_LIST_COMPONENTS_METHOD: &str = "world.list_components";
61
62pub const BRP_MUTATE_COMPONENTS_METHOD: &str = "world.mutate_components";
64
65pub const BRP_GET_COMPONENTS_AND_WATCH_METHOD: &str = "world.get_components+watch";
67
68pub const BRP_LIST_COMPONENTS_AND_WATCH_METHOD: &str = "world.list_components+watch";
70
71pub const BRP_GET_RESOURCE_METHOD: &str = "world.get_resources";
73
74pub const BRP_INSERT_RESOURCE_METHOD: &str = "world.insert_resources";
76
77pub const BRP_REMOVE_RESOURCE_METHOD: &str = "world.remove_resources";
79
80pub const BRP_MUTATE_RESOURCE_METHOD: &str = "world.mutate_resources";
82
83pub const BRP_LIST_RESOURCES_METHOD: &str = "world.list_resources";
85
86pub const BRP_TRIGGER_EVENT_METHOD: &str = "world.trigger_event";
88
89pub const BRP_REGISTRY_SCHEMA_METHOD: &str = "registry.schema";
91
92pub const RPC_DISCOVER_METHOD: &str = "rpc.discover";
94
95#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
100pub struct BrpGetComponentsParams {
101 pub entity: Entity,
103
104 pub components: Vec<String>,
113
114 #[serde(default)]
117 pub strict: bool,
118}
119
120#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
122pub struct BrpGetResourcesParams {
123 pub resource: String,
127}
128
129#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
134pub struct BrpQueryParams {
135 pub data: BrpQuery,
137
138 #[serde(default)]
141 pub filter: BrpQueryFilter,
142
143 #[serde(default)]
146 pub strict: bool,
147}
148
149#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
154pub struct BrpSpawnEntityParams {
155 pub components: HashMap<String, Value>,
165}
166
167#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
171pub struct BrpDespawnEntityParams {
172 pub entity: Entity,
174}
175
176#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
180pub struct BrpRemoveComponentsParams {
181 pub entity: Entity,
183
184 pub components: Vec<String>,
193}
194
195#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
197pub struct BrpRemoveResourcesParams {
198 pub resource: String,
202}
203
204#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
208pub struct BrpInsertComponentsParams {
209 pub entity: Entity,
211
212 pub components: HashMap<String, Value>,
222}
223
224#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
227pub struct BrpInsertResourcesParams {
228 pub resource: String,
232
233 pub value: Value,
235}
236
237#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
241pub struct BrpReparentEntitiesParams {
242 pub entities: Vec<Entity>,
245
246 #[serde(default)]
251 pub parent: Option<Entity>,
252}
253
254#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
259pub struct BrpListComponentsParams {
260 pub entity: Entity,
262}
263
264#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
268pub struct BrpMutateComponentsParams {
269 pub entity: Entity,
271
272 pub component: String,
276
277 pub path: String,
281
282 pub value: Value,
284}
285
286#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
290pub struct BrpMutateResourcesParams {
291 pub resource: String,
295
296 pub path: String,
300
301 pub value: Value,
303}
304
305#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
309struct BrpTriggerEventParams {
310 pub event: String,
314 pub value: Option<Value>,
316}
317
318#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq)]
320pub struct BrpQuery {
321 #[serde(default)]
326 pub components: Vec<String>,
327
328 #[serde(default)]
333 pub option: ComponentSelector,
334
335 #[serde(default)]
340 pub has: Vec<String>,
341}
342
343#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq)]
346pub struct BrpQueryFilter {
347 #[serde(default)]
352 pub without: Vec<String>,
353
354 #[serde(default)]
359 pub with: Vec<String>,
360}
361
362#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq)]
365pub struct BrpJsonSchemaQueryFilter {
366 #[serde(skip_serializing_if = "Vec::is_empty", default)]
369 pub without_crates: Vec<String>,
370
371 #[serde(skip_serializing_if = "Vec::is_empty", default)]
374 pub with_crates: Vec<String>,
375
376 #[serde(default)]
378 pub type_limit: JsonSchemaTypeLimit,
379}
380
381#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq)]
384pub struct JsonSchemaTypeLimit {
385 #[serde(skip_serializing_if = "Vec::is_empty", default)]
387 pub without: Vec<String>,
388
389 #[serde(skip_serializing_if = "Vec::is_empty", default)]
391 pub with: Vec<String>,
392}
393
394#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
398pub struct BrpSpawnEntityResponse {
399 pub entity: Entity,
401}
402
403#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
405#[serde(untagged)]
406pub enum BrpGetComponentsResponse {
407 Lenient {
409 components: HashMap<String, Value>,
411 errors: HashMap<String, Value>,
413 },
414 Strict(HashMap<String, Value>),
417}
418
419#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
421pub struct BrpGetResourcesResponse {
422 pub value: Value,
424}
425
426#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
428#[serde(untagged)]
429pub enum BrpGetComponentsWatchingResponse {
430 Lenient {
432 components: HashMap<String, Value>,
435 removed: Vec<String>,
437 errors: HashMap<String, Value>,
439 },
440 Strict {
443 components: HashMap<String, Value>,
446 removed: Vec<String>,
448 },
449}
450
451pub type BrpListComponentsResponse = Vec<String>;
453
454pub type BrpListResourcesResponse = Vec<String>;
456
457#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
459pub struct BrpListComponentsWatchingResponse {
460 added: Vec<String>,
461 removed: Vec<String>,
462}
463
464pub type BrpQueryResponse = Vec<BrpQueryRow>;
466
467#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
469pub struct BrpQueryRow {
470 pub entity: Entity,
472
473 pub components: HashMap<String, Value>,
475
476 #[serde(skip_serializing_if = "HashMap::is_empty", default)]
478 pub has: HashMap<String, Value>,
479}
480
481pub 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
490pub 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
502pub 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
522pub 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 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 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
561pub 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
660fn 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
700fn 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 let Some(reflected) = reflect_component.reflect(entity_ref) else {
712 return Err(BrpError::component_not_present(component_path, entity));
713 };
714
715 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#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
741#[serde(rename_all = "snake_case")]
742pub enum ComponentSelector {
743 All,
745 #[serde(untagged)]
747 Paths(Vec<String>),
748}
749
750impl Default for ComponentSelector {
751 fn default() -> Self {
752 Self::Paths(Vec::default())
753 }
754}
755
756pub 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 let (required, unregistered_in_required) =
784 get_component_ids(&type_registry, world, components.clone(), strict)
785 .map_err(BrpError::component_error)?;
786
787 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 let (has_ids, unregistered_in_has) =
798 get_component_ids(&type_registry, world, has, strict).map_err(BrpError::component_error)?;
799
800 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 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 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 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 match &option {
863 ComponentSelector::All => {
864 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 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 let optionals = optional.iter().filter(|(_, component_id)| {
888 !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 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
920fn 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 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
957pub 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
978pub 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
1016pub 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
1035pub 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
1058pub 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 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 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 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 let value: Box<dyn PartialReflect> = TypedReflectDeserializer::new(value_type, &type_registry)
1109 .deserialize(&value)
1110 .map_err(BrpError::component_error)?;
1111
1112 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
1122pub 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 let reflect_resource =
1138 get_reflect_resource(&type_registry, &resource_path).map_err(BrpError::resource_error)?;
1139
1140 let mut reflected_resource = reflect_resource
1142 .reflect_mut(world)
1143 .map_err(|_| BrpError::resource_not_present(&resource_path))?;
1144
1145 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 let deserialized_value: Box<dyn PartialReflect> =
1159 TypedReflectDeserializer::new(value_registration, &type_registry)
1160 .deserialize(&value)
1161 .map_err(BrpError::resource_error)?;
1162
1163 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
1173pub 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 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
1202pub 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
1221pub 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
1233pub 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 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 else {
1256 for entity in entities {
1257 get_entity_mut(world, entity)?.remove::<ChildOf>();
1258 }
1259 }
1260
1261 Ok(Value::Null)
1262}
1263
1264pub 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 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 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 response.sort();
1296
1297 serde_json::to_value(response).map_err(BrpError::internal)
1298}
1299
1300pub 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
1321pub 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
1367pub 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, ®istry)
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, ®istry);
1396 } else {
1397 let payload = DynamicStruct::default();
1398 reflect_event.trigger(world, &payload, ®istry);
1399 }
1400
1401 Ok(Value::Null)
1402 })
1403}
1404
1405pub 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
1458fn 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
1466fn 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
1474fn 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
1514fn 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
1538fn 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
1563fn 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
1585fn 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
1602fn 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
1615fn 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
1628fn 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
1639fn 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
1652fn 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 fn test_serialize_deserialize<T>(value: T)
1668 where
1669 T: Serialize + for<'a> Deserialize<'a> + PartialEq + core::fmt::Debug,
1670 {
1671 let serialized = serde_json::to_string(&value).expect("Failed to serialize");
1673
1674 let deserialized: T = serde_json::from_str(&serialized).expect("Failed to deserialize");
1676
1677 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}