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