Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_remote/src/builtin_methods.rs
6849 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
hierarchy::ChildOf,
10
lifecycle::RemovedComponentEntity,
11
message::MessageCursor,
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, MessageCursor<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
.iter_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(entity, reflect_components).map_err(BrpError::component_error)?;
956
957
let response = BrpSpawnEntityResponse { entity: entity_id };
958
serde_json::to_value(response).map_err(BrpError::internal)
959
}
960
961
/// Handles a `rpc.discover` request coming from a client.
962
pub fn process_remote_list_methods_request(
963
In(_params): In<Option<Value>>,
964
world: &mut World,
965
) -> BrpResult {
966
let remote_methods = world.resource::<crate::RemoteMethods>();
967
968
#[cfg(all(feature = "http", not(target_family = "wasm")))]
969
let servers = match (
970
world.get_resource::<crate::http::HostAddress>(),
971
world.get_resource::<crate::http::HostPort>(),
972
) {
973
(Some(url), Some(port)) => Some(vec![ServerObject {
974
name: "Server".to_owned(),
975
url: format!("{}:{}", url.0, port.0),
976
..default()
977
}]),
978
(Some(url), None) => Some(vec![ServerObject {
979
name: "Server".to_owned(),
980
url: url.0.to_string(),
981
..default()
982
}]),
983
_ => None,
984
};
985
986
#[cfg(any(not(feature = "http"), target_family = "wasm"))]
987
let servers = None;
988
989
let doc = OpenRpcDocument {
990
info: Default::default(),
991
methods: remote_methods.into(),
992
openrpc: "1.3.2".to_owned(),
993
servers,
994
};
995
996
serde_json::to_value(doc).map_err(BrpError::internal)
997
}
998
999
/// Handles a `world.insert_components` request (insert components) coming from a client.
1000
pub fn process_remote_insert_components_request(
1001
In(params): In<Option<Value>>,
1002
world: &mut World,
1003
) -> BrpResult {
1004
let BrpInsertComponentsParams { entity, components } = parse_some(params)?;
1005
1006
let app_type_registry = world.resource::<AppTypeRegistry>().clone();
1007
let type_registry = app_type_registry.read();
1008
1009
let reflect_components =
1010
deserialize_components(&type_registry, components).map_err(BrpError::component_error)?;
1011
1012
insert_reflected_components(get_entity_mut(world, entity)?, reflect_components)
1013
.map_err(BrpError::component_error)?;
1014
1015
Ok(Value::Null)
1016
}
1017
1018
/// Handles a `world.insert_resources` request coming from a client.
1019
pub fn process_remote_insert_resources_request(
1020
In(params): In<Option<Value>>,
1021
world: &mut World,
1022
) -> BrpResult {
1023
let BrpInsertResourcesParams {
1024
resource: resource_path,
1025
value,
1026
} = parse_some(params)?;
1027
1028
let app_type_registry = world.resource::<AppTypeRegistry>().clone();
1029
let type_registry = app_type_registry.read();
1030
1031
let reflected_resource = deserialize_resource(&type_registry, &resource_path, value)
1032
.map_err(BrpError::resource_error)?;
1033
1034
let reflect_resource =
1035
get_reflect_resource(&type_registry, &resource_path).map_err(BrpError::resource_error)?;
1036
reflect_resource.insert(world, &*reflected_resource, &type_registry);
1037
1038
Ok(Value::Null)
1039
}
1040
1041
/// Handles a `world.mutate_components` request coming from a client.
1042
///
1043
/// This method allows you to mutate a single field inside an Entity's
1044
/// component.
1045
pub fn process_remote_mutate_components_request(
1046
In(params): In<Option<Value>>,
1047
world: &mut World,
1048
) -> BrpResult {
1049
let BrpMutateComponentsParams {
1050
entity,
1051
component,
1052
path,
1053
value,
1054
} = parse_some(params)?;
1055
let app_type_registry = world.resource::<AppTypeRegistry>().clone();
1056
let type_registry = app_type_registry.read();
1057
1058
// Get the fully-qualified type names of the component to be mutated.
1059
let component_type: &TypeRegistration = type_registry
1060
.get_with_type_path(&component)
1061
.ok_or_else(|| {
1062
BrpError::component_error(anyhow!("Unknown component type: `{}`", component))
1063
})?;
1064
1065
// Get the reflected representation of the component.
1066
let mut reflected = component_type
1067
.data::<ReflectComponent>()
1068
.ok_or_else(|| {
1069
BrpError::component_error(anyhow!("Component `{}` isn't registered", component))
1070
})?
1071
.reflect_mut(world.entity_mut(entity))
1072
.ok_or_else(|| {
1073
BrpError::component_error(anyhow!("Cannot reflect component `{}`", component))
1074
})?;
1075
1076
// Get the type of the field in the component that is to be
1077
// mutated.
1078
let value_type: &TypeRegistration = type_registry
1079
.get_with_type_path(
1080
reflected
1081
.reflect_path(path.as_str())
1082
.map_err(BrpError::component_error)?
1083
.reflect_type_path(),
1084
)
1085
.ok_or_else(|| {
1086
BrpError::component_error(anyhow!("Unknown component field type: `{}`", component))
1087
})?;
1088
1089
// Get the reflected representation of the value to be inserted
1090
// into the component.
1091
let value: Box<dyn PartialReflect> = TypedReflectDeserializer::new(value_type, &type_registry)
1092
.deserialize(&value)
1093
.map_err(BrpError::component_error)?;
1094
1095
// Apply the mutation.
1096
reflected
1097
.reflect_path_mut(path.as_str())
1098
.map_err(BrpError::component_error)?
1099
.try_apply(value.as_ref())
1100
.map_err(BrpError::component_error)?;
1101
1102
Ok(Value::Null)
1103
}
1104
1105
/// Handles a `world.mutate_resources` request coming from a client.
1106
pub fn process_remote_mutate_resources_request(
1107
In(params): In<Option<Value>>,
1108
world: &mut World,
1109
) -> BrpResult {
1110
let BrpMutateResourcesParams {
1111
resource: resource_path,
1112
path: field_path,
1113
value,
1114
} = parse_some(params)?;
1115
1116
let app_type_registry = world.resource::<AppTypeRegistry>().clone();
1117
let type_registry = app_type_registry.read();
1118
1119
// Get the `ReflectResource` for the given resource path.
1120
let reflect_resource =
1121
get_reflect_resource(&type_registry, &resource_path).map_err(BrpError::resource_error)?;
1122
1123
// Get the actual resource value from the world as a `dyn Reflect`.
1124
let mut reflected_resource = reflect_resource
1125
.reflect_mut(world)
1126
.map_err(|_| BrpError::resource_not_present(&resource_path))?;
1127
1128
// Get the type registration for the field with the given path.
1129
let value_registration = type_registry
1130
.get_with_type_path(
1131
reflected_resource
1132
.reflect_path(field_path.as_str())
1133
.map_err(BrpError::resource_error)?
1134
.reflect_type_path(),
1135
)
1136
.ok_or_else(|| {
1137
BrpError::resource_error(anyhow!("Unknown resource field type: `{}`", resource_path))
1138
})?;
1139
1140
// Use the field's type registration to deserialize the given value.
1141
let deserialized_value: Box<dyn PartialReflect> =
1142
TypedReflectDeserializer::new(value_registration, &type_registry)
1143
.deserialize(&value)
1144
.map_err(BrpError::resource_error)?;
1145
1146
// Apply the value to the resource.
1147
reflected_resource
1148
.reflect_path_mut(field_path.as_str())
1149
.map_err(BrpError::resource_error)?
1150
.try_apply(&*deserialized_value)
1151
.map_err(BrpError::resource_error)?;
1152
1153
Ok(Value::Null)
1154
}
1155
1156
/// Handles a `world.remove_components` request (remove components) coming from a client.
1157
pub fn process_remote_remove_components_request(
1158
In(params): In<Option<Value>>,
1159
world: &mut World,
1160
) -> BrpResult {
1161
let BrpRemoveComponentsParams { entity, components } = parse_some(params)?;
1162
1163
let app_type_registry = world.resource::<AppTypeRegistry>().clone();
1164
let type_registry = app_type_registry.read();
1165
1166
let component_ids = get_component_ids(&type_registry, world, components, true)
1167
.and_then(|(registered, unregistered)| {
1168
if unregistered.is_empty() {
1169
Ok(registered)
1170
} else {
1171
Err(anyhow!("Unregistered component types: {:?}", unregistered))
1172
}
1173
})
1174
.map_err(BrpError::component_error)?;
1175
1176
// Remove the components.
1177
let mut entity_world_mut = get_entity_mut(world, entity)?;
1178
for (_, component_id) in component_ids.iter() {
1179
entity_world_mut.remove_by_id(*component_id);
1180
}
1181
1182
Ok(Value::Null)
1183
}
1184
1185
/// Handles a `world.remove_resources` request coming from a client.
1186
pub fn process_remote_remove_resources_request(
1187
In(params): In<Option<Value>>,
1188
world: &mut World,
1189
) -> BrpResult {
1190
let BrpRemoveResourcesParams {
1191
resource: resource_path,
1192
} = parse_some(params)?;
1193
1194
let app_type_registry = world.resource::<AppTypeRegistry>().clone();
1195
let type_registry = app_type_registry.read();
1196
1197
let reflect_resource =
1198
get_reflect_resource(&type_registry, &resource_path).map_err(BrpError::resource_error)?;
1199
reflect_resource.remove(world);
1200
1201
Ok(Value::Null)
1202
}
1203
1204
/// Handles a `world.despawn_entity` (despawn entity) request coming from a client.
1205
pub fn process_remote_despawn_entity_request(
1206
In(params): In<Option<Value>>,
1207
world: &mut World,
1208
) -> BrpResult {
1209
let BrpDespawnEntityParams { entity } = parse_some(params)?;
1210
1211
get_entity_mut(world, entity)?.despawn();
1212
1213
Ok(Value::Null)
1214
}
1215
1216
/// Handles a `world.reparent_entities` request coming from a client.
1217
pub fn process_remote_reparent_entities_request(
1218
In(params): In<Option<Value>>,
1219
world: &mut World,
1220
) -> BrpResult {
1221
let BrpReparentEntitiesParams {
1222
entities,
1223
parent: maybe_parent,
1224
} = parse_some(params)?;
1225
1226
// If `Some`, reparent the entities.
1227
if let Some(parent) = maybe_parent {
1228
let mut parent_commands =
1229
get_entity_mut(world, parent).map_err(|_| BrpError::entity_not_found(parent))?;
1230
for entity in entities {
1231
if entity == parent {
1232
return Err(BrpError::self_reparent(entity));
1233
}
1234
parent_commands.add_child(entity);
1235
}
1236
}
1237
// If `None`, remove the entities' parents.
1238
else {
1239
for entity in entities {
1240
get_entity_mut(world, entity)?.remove::<ChildOf>();
1241
}
1242
}
1243
1244
Ok(Value::Null)
1245
}
1246
1247
/// Handles a `world.list_components` request (list all components) coming from a client.
1248
pub fn process_remote_list_components_request(
1249
In(params): In<Option<Value>>,
1250
world: &World,
1251
) -> BrpResult {
1252
let app_type_registry = world.resource::<AppTypeRegistry>();
1253
let type_registry = app_type_registry.read();
1254
1255
let mut response = BrpListComponentsResponse::default();
1256
1257
// If `Some`, return all components of the provided entity.
1258
if let Some(BrpListComponentsParams { entity }) = params.map(parse).transpose()? {
1259
let entity = get_entity(world, entity)?;
1260
for component_id in entity.archetype().iter_components() {
1261
let Some(component_info) = world.components().get_info(component_id) else {
1262
continue;
1263
};
1264
response.push(component_info.name().to_string());
1265
}
1266
}
1267
// If `None`, list all registered components.
1268
else {
1269
for registered_type in type_registry.iter() {
1270
if registered_type.data::<ReflectComponent>().is_some() {
1271
response.push(registered_type.type_info().type_path().to_owned());
1272
}
1273
}
1274
}
1275
1276
// Sort both for cleanliness and to reduce the risk that clients start
1277
// accidentally depending on the order.
1278
response.sort();
1279
1280
serde_json::to_value(response).map_err(BrpError::internal)
1281
}
1282
1283
/// Handles a `world.list_resources` request coming from a client.
1284
pub fn process_remote_list_resources_request(
1285
In(_params): In<Option<Value>>,
1286
world: &World,
1287
) -> BrpResult {
1288
let mut response = BrpListResourcesResponse::default();
1289
1290
let app_type_registry = world.resource::<AppTypeRegistry>();
1291
let type_registry = app_type_registry.read();
1292
1293
for registered_type in type_registry.iter() {
1294
if registered_type.data::<ReflectResource>().is_some() {
1295
response.push(registered_type.type_info().type_path().to_owned());
1296
}
1297
}
1298
1299
response.sort();
1300
1301
serde_json::to_value(response).map_err(BrpError::internal)
1302
}
1303
1304
/// Handles a `world.list_components+watch` request coming from a client.
1305
pub fn process_remote_list_components_watching_request(
1306
In(params): In<Option<Value>>,
1307
world: &World,
1308
mut removal_cursors: Local<HashMap<ComponentId, MessageCursor<RemovedComponentEntity>>>,
1309
) -> BrpResult<Option<Value>> {
1310
let BrpListComponentsParams { entity } = parse_some(params)?;
1311
let entity_ref = get_entity(world, entity)?;
1312
let mut response = BrpListComponentsWatchingResponse::default();
1313
1314
for component_id in entity_ref.archetype().iter_components() {
1315
let ticks = entity_ref
1316
.get_change_ticks_by_id(component_id)
1317
.ok_or(BrpError::internal("Failed to get ticks"))?;
1318
1319
if ticks.is_added(world.last_change_tick(), world.read_change_tick()) {
1320
let Some(component_info) = world.components().get_info(component_id) else {
1321
continue;
1322
};
1323
response.added.push(component_info.name().to_string());
1324
}
1325
}
1326
1327
for (component_id, events) in world.removed_components().iter() {
1328
let cursor = removal_cursors
1329
.entry(*component_id)
1330
.or_insert_with(|| events.get_cursor());
1331
for event in cursor.read(events) {
1332
if Entity::from(event.clone()) == entity {
1333
let Some(component_info) = world.components().get_info(*component_id) else {
1334
continue;
1335
};
1336
response.removed.push(component_info.name().to_string());
1337
}
1338
}
1339
}
1340
1341
if response.added.is_empty() && response.removed.is_empty() {
1342
Ok(None)
1343
} else {
1344
Ok(Some(
1345
serde_json::to_value(response).map_err(BrpError::internal)?,
1346
))
1347
}
1348
}
1349
1350
/// Handles a `registry.schema` request (list all registry types in form of schema) coming from a client.
1351
pub fn export_registry_types(In(params): In<Option<Value>>, world: &World) -> BrpResult {
1352
let filter: BrpJsonSchemaQueryFilter = match params {
1353
None => Default::default(),
1354
Some(params) => parse(params)?,
1355
};
1356
1357
let extra_info = world.resource::<crate::schemas::SchemaTypesMetadata>();
1358
let types = world.resource::<AppTypeRegistry>();
1359
let types = types.read();
1360
let schemas = types
1361
.iter()
1362
.filter_map(|type_reg| {
1363
let path_table = type_reg.type_info().type_path_table();
1364
if let Some(crate_name) = &path_table.crate_name() {
1365
if !filter.with_crates.is_empty()
1366
&& !filter.with_crates.iter().any(|c| crate_name.eq(c))
1367
{
1368
return None;
1369
}
1370
if !filter.without_crates.is_empty()
1371
&& filter.without_crates.iter().any(|c| crate_name.eq(c))
1372
{
1373
return None;
1374
}
1375
}
1376
let (id, schema) = export_type(type_reg, extra_info);
1377
1378
if !filter.type_limit.with.is_empty()
1379
&& !filter
1380
.type_limit
1381
.with
1382
.iter()
1383
.any(|c| schema.reflect_types.iter().any(|cc| c.eq(cc)))
1384
{
1385
return None;
1386
}
1387
if !filter.type_limit.without.is_empty()
1388
&& filter
1389
.type_limit
1390
.without
1391
.iter()
1392
.any(|c| schema.reflect_types.iter().any(|cc| c.eq(cc)))
1393
{
1394
return None;
1395
}
1396
Some((id.to_string(), schema))
1397
})
1398
.collect::<HashMap<String, JsonSchemaBevyType>>();
1399
1400
serde_json::to_value(schemas).map_err(BrpError::internal)
1401
}
1402
1403
/// Immutably retrieves an entity from the [`World`], returning an error if the
1404
/// entity isn't present.
1405
fn get_entity(world: &World, entity: Entity) -> Result<EntityRef<'_>, BrpError> {
1406
world
1407
.get_entity(entity)
1408
.map_err(|_| BrpError::entity_not_found(entity))
1409
}
1410
1411
/// Mutably retrieves an entity from the [`World`], returning an error if the
1412
/// entity isn't present.
1413
fn get_entity_mut(world: &mut World, entity: Entity) -> Result<EntityWorldMut<'_>, BrpError> {
1414
world
1415
.get_entity_mut(entity)
1416
.map_err(|_| BrpError::entity_not_found(entity))
1417
}
1418
1419
/// Given components full path, returns a tuple that contains
1420
/// - A list of corresponding [`TypeId`] and [`ComponentId`] for registered components.
1421
/// - A list of unregistered component paths.
1422
///
1423
/// Note that the supplied path names must be *full* path names: e.g.
1424
/// `bevy_transform::components::transform::Transform` instead of `Transform`.
1425
fn get_component_ids(
1426
type_registry: &TypeRegistry,
1427
world: &World,
1428
component_paths: Vec<String>,
1429
strict: bool,
1430
) -> AnyhowResult<(Vec<(TypeId, ComponentId)>, Vec<String>)> {
1431
let mut component_ids = vec![];
1432
let mut unregistered_components = vec![];
1433
1434
for component_path in component_paths {
1435
let maybe_component_tuple = get_component_type_registration(type_registry, &component_path)
1436
.ok()
1437
.and_then(|type_registration| {
1438
let type_id = type_registration.type_id();
1439
world
1440
.components()
1441
.get_valid_id(type_id)
1442
.map(|component_id| (type_id, component_id))
1443
});
1444
if let Some((type_id, component_id)) = maybe_component_tuple {
1445
component_ids.push((type_id, component_id));
1446
} else if strict {
1447
return Err(anyhow!(
1448
"Component `{}` isn't registered or used in the world",
1449
component_path
1450
));
1451
} else {
1452
unregistered_components.push(component_path);
1453
}
1454
}
1455
1456
Ok((component_ids, unregistered_components))
1457
}
1458
1459
/// Given an entity (`entity_ref`),
1460
/// a list of reflected component information (`paths_and_reflect_components`)
1461
/// and a list of unregistered components,
1462
/// return a map which associates each component to a boolean value indicating
1463
/// whether or not that component is present on the entity.
1464
/// Unregistered components are considered absent from the entity.
1465
fn build_has_map<'a>(
1466
entity_ref: FilteredEntityRef,
1467
paths_and_reflect_components: impl Iterator<Item = (&'a str, &'a ReflectComponent)>,
1468
unregistered_components: &[String],
1469
) -> HashMap<String, Value> {
1470
let mut has_map = <HashMap<_, _>>::default();
1471
1472
for (type_path, reflect_component) in paths_and_reflect_components {
1473
let has = reflect_component.contains(entity_ref);
1474
has_map.insert(type_path.to_owned(), Value::Bool(has));
1475
}
1476
unregistered_components.iter().for_each(|component| {
1477
has_map.insert(component.to_owned(), Value::Bool(false));
1478
});
1479
1480
has_map
1481
}
1482
1483
/// Given a component ID, return the associated [type path] and `ReflectComponent` if possible.
1484
///
1485
/// The `ReflectComponent` part is the meat of this; the type path is only used for error messages.
1486
///
1487
/// [type path]: bevy_reflect::TypePath::type_path
1488
fn reflect_component_from_id(
1489
component_type_id: TypeId,
1490
type_registry: &TypeRegistry,
1491
) -> AnyhowResult<(&str, &ReflectComponent)> {
1492
let Some(type_registration) = type_registry.get(component_type_id) else {
1493
return Err(anyhow!(
1494
"Component `{:?}` isn't registered",
1495
component_type_id
1496
));
1497
};
1498
1499
let type_path = type_registration.type_info().type_path();
1500
1501
let Some(reflect_component) = type_registration.data::<ReflectComponent>() else {
1502
return Err(anyhow!("Component `{}` isn't reflectable", type_path));
1503
};
1504
1505
Ok((type_path, reflect_component))
1506
}
1507
1508
/// Given a collection of component paths and their associated serialized values (`components`),
1509
/// return the associated collection of deserialized reflected values.
1510
fn deserialize_components(
1511
type_registry: &TypeRegistry,
1512
components: HashMap<String, Value>,
1513
) -> AnyhowResult<Vec<Box<dyn PartialReflect>>> {
1514
let mut reflect_components = vec![];
1515
1516
for (component_path, component) in components {
1517
let Some(component_type) = type_registry.get_with_type_path(&component_path) else {
1518
return Err(anyhow!("Unknown component type: `{}`", component_path));
1519
};
1520
let reflected: Box<dyn PartialReflect> =
1521
TypedReflectDeserializer::new(component_type, type_registry)
1522
.deserialize(&component)
1523
.map_err(|err| anyhow!("{component_path} is invalid: {err}"))?;
1524
reflect_components.push(reflected);
1525
}
1526
1527
Ok(reflect_components)
1528
}
1529
1530
/// Given a resource path and an associated serialized value (`value`), return the
1531
/// deserialized value.
1532
fn deserialize_resource(
1533
type_registry: &TypeRegistry,
1534
resource_path: &str,
1535
value: Value,
1536
) -> AnyhowResult<Box<dyn PartialReflect>> {
1537
let Some(resource_type) = type_registry.get_with_type_path(resource_path) else {
1538
return Err(anyhow!("Unknown resource type: `{}`", resource_path));
1539
};
1540
let reflected: Box<dyn PartialReflect> =
1541
TypedReflectDeserializer::new(resource_type, type_registry)
1542
.deserialize(&value)
1543
.map_err(|err| anyhow!("{resource_path} is invalid: {err}"))?;
1544
Ok(reflected)
1545
}
1546
1547
/// Given a collection `reflect_components` of reflected component values, insert them into
1548
/// the given entity (`entity_world_mut`).
1549
fn insert_reflected_components(
1550
mut entity_world_mut: EntityWorldMut,
1551
reflect_components: Vec<Box<dyn PartialReflect>>,
1552
) -> AnyhowResult<()> {
1553
for reflected in reflect_components {
1554
entity_world_mut.insert_reflect(reflected);
1555
}
1556
1557
Ok(())
1558
}
1559
1560
/// Given a component's type path, return the associated [`ReflectComponent`] from the given
1561
/// `type_registry` if possible.
1562
fn get_reflect_component<'r>(
1563
type_registry: &'r TypeRegistry,
1564
component_path: &str,
1565
) -> AnyhowResult<&'r ReflectComponent> {
1566
let component_registration = get_component_type_registration(type_registry, component_path)?;
1567
1568
component_registration
1569
.data::<ReflectComponent>()
1570
.ok_or_else(|| anyhow!("Component `{}` isn't reflectable", component_path))
1571
}
1572
1573
/// Given a component's type path, return the associated [`TypeRegistration`] from the given
1574
/// `type_registry` if possible.
1575
fn get_component_type_registration<'r>(
1576
type_registry: &'r TypeRegistry,
1577
component_path: &str,
1578
) -> AnyhowResult<&'r TypeRegistration> {
1579
type_registry
1580
.get_with_type_path(component_path)
1581
.ok_or_else(|| anyhow!("Unknown component type: `{}`", component_path))
1582
}
1583
1584
/// Given a resource's type path, return the associated [`ReflectResource`] from the given
1585
/// `type_registry` if possible.
1586
fn get_reflect_resource<'r>(
1587
type_registry: &'r TypeRegistry,
1588
resource_path: &str,
1589
) -> AnyhowResult<&'r ReflectResource> {
1590
let resource_registration = get_resource_type_registration(type_registry, resource_path)?;
1591
1592
resource_registration
1593
.data::<ReflectResource>()
1594
.ok_or_else(|| anyhow!("Resource `{}` isn't reflectable", resource_path))
1595
}
1596
1597
/// Given a resource's type path, return the associated [`TypeRegistration`] from the given
1598
/// `type_registry` if possible.
1599
fn get_resource_type_registration<'r>(
1600
type_registry: &'r TypeRegistry,
1601
resource_path: &str,
1602
) -> AnyhowResult<&'r TypeRegistration> {
1603
type_registry
1604
.get_with_type_path(resource_path)
1605
.ok_or_else(|| anyhow!("Unknown resource type: `{}`", resource_path))
1606
}
1607
1608
#[cfg(test)]
1609
mod tests {
1610
/// A generic function that tests serialization and deserialization of any type
1611
/// implementing Serialize and Deserialize traits.
1612
fn test_serialize_deserialize<T>(value: T)
1613
where
1614
T: Serialize + for<'a> Deserialize<'a> + PartialEq + core::fmt::Debug,
1615
{
1616
// Serialize the value to JSON string
1617
let serialized = serde_json::to_string(&value).expect("Failed to serialize");
1618
1619
// Deserialize the JSON string back into the original type
1620
let deserialized: T = serde_json::from_str(&serialized).expect("Failed to deserialize");
1621
1622
// Assert that the deserialized value is the same as the original
1623
assert_eq!(
1624
&value, &deserialized,
1625
"Deserialized value does not match original"
1626
);
1627
}
1628
1629
use super::*;
1630
1631
#[test]
1632
fn insert_reflect_only_component() {
1633
use bevy_ecs::prelude::Component;
1634
use bevy_reflect::Reflect;
1635
#[derive(Reflect, Component)]
1636
#[reflect(Component)]
1637
struct Player {
1638
name: String,
1639
health: u32,
1640
}
1641
let components: HashMap<String, Value> = [(
1642
String::from("bevy_remote::builtin_methods::tests::Player"),
1643
serde_json::json!({"name": "John", "health": 50}),
1644
)]
1645
.into();
1646
let atr = AppTypeRegistry::default();
1647
{
1648
let mut register = atr.write();
1649
register.register::<Player>();
1650
}
1651
let deserialized_components = {
1652
let type_reg = atr.read();
1653
deserialize_components(&type_reg, components).expect("FAIL")
1654
};
1655
let mut world = World::new();
1656
world.insert_resource(atr);
1657
let e = world.spawn_empty();
1658
insert_reflected_components(e, deserialized_components).expect("FAIL");
1659
}
1660
1661
#[test]
1662
fn serialization_tests() {
1663
test_serialize_deserialize(BrpQueryRow {
1664
components: Default::default(),
1665
entity: Entity::from_raw_u32(0).unwrap(),
1666
has: Default::default(),
1667
});
1668
test_serialize_deserialize(BrpListComponentsWatchingResponse::default());
1669
test_serialize_deserialize(BrpQuery::default());
1670
test_serialize_deserialize(BrpJsonSchemaQueryFilter::default());
1671
test_serialize_deserialize(BrpJsonSchemaQueryFilter {
1672
type_limit: JsonSchemaTypeLimit {
1673
with: vec!["Resource".to_owned()],
1674
..Default::default()
1675
},
1676
..Default::default()
1677
});
1678
test_serialize_deserialize(BrpListComponentsParams {
1679
entity: Entity::from_raw_u32(0).unwrap(),
1680
});
1681
}
1682
}
1683
1684