Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_scene/src/dynamic_scene_builder.rs
9421 views
1
use core::any::TypeId;
2
3
use crate::reflect_utils::clone_reflect_value;
4
use crate::{DynamicEntity, DynamicScene, SceneFilter};
5
use alloc::collections::BTreeMap;
6
use bevy_ecs::resource::IS_RESOURCE;
7
use bevy_ecs::{
8
component::{Component, ComponentId},
9
entity_disabling::DefaultQueryFilters,
10
prelude::Entity,
11
reflect::{AppTypeRegistry, ReflectComponent, ReflectResource},
12
resource::Resource,
13
world::World,
14
};
15
use bevy_reflect::PartialReflect;
16
use bevy_utils::default;
17
18
/// A [`DynamicScene`] builder, used to build a scene from a [`World`] by extracting some entities and resources.
19
///
20
/// # Component Extraction
21
///
22
/// By default, all components registered with [`ReflectComponent`] type data in a world's [`AppTypeRegistry`] will be extracted.
23
/// (this type data is added automatically during registration if [`Reflect`] is derived with the `#[reflect(Component)]` attribute).
24
/// This can be changed by [specifying a filter](DynamicSceneBuilder::with_component_filter) or by explicitly
25
/// [allowing](DynamicSceneBuilder::allow_component)/[denying](DynamicSceneBuilder::deny_component) certain components.
26
///
27
/// Extraction happens immediately and uses the filter as it exists during the time of extraction.
28
///
29
/// # Resource Extraction
30
///
31
/// By default, all resources registered with [`ReflectResource`] type data in a world's [`AppTypeRegistry`] will be extracted.
32
/// (this type data is added automatically during registration if [`Reflect`] is derived with the `#[reflect(Resource)]` attribute).
33
/// This can be changed by [specifying a filter](DynamicSceneBuilder::with_resource_filter) or by explicitly
34
/// [allowing](DynamicSceneBuilder::allow_resource)/[denying](DynamicSceneBuilder::deny_resource) certain resources.
35
///
36
/// Extraction happens immediately and uses the filter as it exists during the time of extraction.
37
///
38
/// # Entity Order
39
///
40
/// Extracted entities will always be stored in ascending order based on their [index](Entity::index).
41
/// This means that inserting `Entity(1v0)` then `Entity(0v0)` will always result in the entities
42
/// being ordered as `[Entity(0v0), Entity(1v0)]`.
43
///
44
/// # Example
45
/// ```
46
/// # use bevy_scene::DynamicSceneBuilder;
47
/// # use bevy_ecs::reflect::AppTypeRegistry;
48
/// # use bevy_ecs::{
49
/// # component::Component, prelude::Entity, query::With, reflect::ReflectComponent, world::World,
50
/// # };
51
/// # use bevy_reflect::Reflect;
52
/// # #[derive(Component, Reflect, Default, Eq, PartialEq, Debug)]
53
/// # #[reflect(Component)]
54
/// # struct ComponentA;
55
/// # let mut world = World::default();
56
/// # world.init_resource::<AppTypeRegistry>();
57
/// # let entity = world.spawn(ComponentA).id();
58
/// let dynamic_scene = DynamicSceneBuilder::from_world(&world).extract_entity(entity).build();
59
/// ```
60
///
61
/// [`Reflect`]: bevy_reflect::Reflect
62
pub struct DynamicSceneBuilder<'w> {
63
extracted_resources: BTreeMap<ComponentId, Box<dyn PartialReflect>>,
64
extracted_scene: BTreeMap<Entity, DynamicEntity>,
65
component_filter: SceneFilter,
66
resource_filter: SceneFilter,
67
original_world: &'w World,
68
}
69
70
impl<'w> DynamicSceneBuilder<'w> {
71
/// Prepare a builder that will extract entities and their component from the given [`World`].
72
pub fn from_world(world: &'w World) -> Self {
73
Self {
74
extracted_resources: default(),
75
extracted_scene: default(),
76
component_filter: SceneFilter::default(),
77
resource_filter: SceneFilter::default(),
78
original_world: world,
79
}
80
}
81
82
/// Specify a custom component [`SceneFilter`] to be used with this builder.
83
#[must_use]
84
pub fn with_component_filter(mut self, filter: SceneFilter) -> Self {
85
self.component_filter = filter;
86
self
87
}
88
89
/// Specify a custom resource [`SceneFilter`] to be used with this builder.
90
#[must_use]
91
pub fn with_resource_filter(mut self, filter: SceneFilter) -> Self {
92
self.resource_filter = filter;
93
self
94
}
95
96
/// Updates the filter to allow all component and resource types.
97
///
98
/// This is useful for resetting the filter so that types may be selectively denied
99
/// with [`deny_component`](`Self::deny_component`) and [`deny_resource`](`Self::deny_resource`).
100
pub fn allow_all(mut self) -> Self {
101
self.component_filter = SceneFilter::allow_all();
102
self.resource_filter = SceneFilter::allow_all();
103
self
104
}
105
106
/// Updates the filter to deny all component and resource types.
107
///
108
/// This is useful for resetting the filter so that types may be selectively allowed
109
/// with [`allow_component`](`Self::allow_component`) and [`allow_resource`](`Self::allow_resource`).
110
pub fn deny_all(mut self) -> Self {
111
self.component_filter = SceneFilter::deny_all();
112
self.resource_filter = SceneFilter::deny_all();
113
self
114
}
115
116
/// Allows the given component type, `T`, to be included in the generated scene.
117
///
118
/// This method may be called multiple times for any number of components.
119
///
120
/// This is the inverse of [`deny_component`](Self::deny_component).
121
/// If `T` has already been denied, then it will be removed from the denylist.
122
#[must_use]
123
pub fn allow_component<T: Component>(mut self) -> Self {
124
self.component_filter = self.component_filter.allow::<T>();
125
self
126
}
127
128
/// Denies the given component type, `T`, from being included in the generated scene.
129
///
130
/// This method may be called multiple times for any number of components.
131
///
132
/// This is the inverse of [`allow_component`](Self::allow_component).
133
/// If `T` has already been allowed, then it will be removed from the allowlist.
134
#[must_use]
135
pub fn deny_component<T: Component>(mut self) -> Self {
136
self.component_filter = self.component_filter.deny::<T>();
137
self
138
}
139
140
/// Updates the filter to allow all component types.
141
///
142
/// This is useful for resetting the filter so that types may be selectively [denied].
143
///
144
/// [denied]: Self::deny_component
145
#[must_use]
146
pub fn allow_all_components(mut self) -> Self {
147
self.component_filter = SceneFilter::allow_all();
148
self
149
}
150
151
/// Updates the filter to deny all component types.
152
///
153
/// This is useful for resetting the filter so that types may be selectively [allowed].
154
///
155
/// [allowed]: Self::allow_component
156
#[must_use]
157
pub fn deny_all_components(mut self) -> Self {
158
self.component_filter = SceneFilter::deny_all();
159
self
160
}
161
162
/// Allows the given resource type, `T`, to be included in the generated scene.
163
///
164
/// This method may be called multiple times for any number of resources.
165
///
166
/// This is the inverse of [`deny_resource`](Self::deny_resource).
167
/// If `T` has already been denied, then it will be removed from the denylist.
168
#[must_use]
169
pub fn allow_resource<T: Resource>(mut self) -> Self {
170
self.resource_filter = self.resource_filter.allow::<T>();
171
self
172
}
173
174
/// Denies the given resource type, `T`, from being included in the generated scene.
175
///
176
/// This method may be called multiple times for any number of resources.
177
///
178
/// This is the inverse of [`allow_resource`](Self::allow_resource).
179
/// If `T` has already been allowed, then it will be removed from the allowlist.
180
#[must_use]
181
pub fn deny_resource<T: Resource>(mut self) -> Self {
182
self.resource_filter = self.resource_filter.deny::<T>();
183
self
184
}
185
186
/// Updates the filter to allow all resource types.
187
///
188
/// This is useful for resetting the filter so that types may be selectively [denied].
189
///
190
/// [denied]: Self::deny_resource
191
#[must_use]
192
pub fn allow_all_resources(mut self) -> Self {
193
self.resource_filter = SceneFilter::allow_all();
194
self
195
}
196
197
/// Updates the filter to deny all resource types.
198
///
199
/// This is useful for resetting the filter so that types may be selectively [allowed].
200
///
201
/// [allowed]: Self::allow_resource
202
#[must_use]
203
pub fn deny_all_resources(mut self) -> Self {
204
self.resource_filter = SceneFilter::deny_all();
205
self
206
}
207
208
/// Consume the builder, producing a [`DynamicScene`].
209
///
210
/// To make sure the dynamic scene doesn't contain entities without any components, call
211
/// [`Self::remove_empty_entities`] before building the scene.
212
#[must_use]
213
pub fn build(self) -> DynamicScene {
214
DynamicScene {
215
resources: self.extracted_resources.into_values().collect(),
216
entities: self.extracted_scene.into_values().collect(),
217
}
218
}
219
220
/// Extract one entity from the builder's [`World`].
221
///
222
/// Re-extracting an entity that was already extracted will have no effect.
223
#[must_use]
224
pub fn extract_entity(self, entity: Entity) -> Self {
225
self.extract_entities(core::iter::once(entity))
226
}
227
228
/// Despawns all entities with no components.
229
///
230
/// These were likely created because none of their components were present in the provided type registry upon extraction.
231
#[must_use]
232
pub fn remove_empty_entities(mut self) -> Self {
233
self.extracted_scene
234
.retain(|_, entity| !entity.components.is_empty());
235
236
self
237
}
238
239
/// Extract entities from the builder's [`World`].
240
///
241
/// Re-extracting an entity that was already extracted will have no effect.
242
///
243
/// To control which components are extracted, use the [`allow`] or
244
/// [`deny`] helper methods.
245
///
246
/// This method may be used to extract entities from a query:
247
/// ```
248
/// # use bevy_scene::DynamicSceneBuilder;
249
/// # use bevy_ecs::reflect::AppTypeRegistry;
250
/// # use bevy_ecs::{
251
/// # component::Component, prelude::Entity, query::With, reflect::ReflectComponent, world::World,
252
/// # };
253
/// # use bevy_reflect::Reflect;
254
/// #[derive(Component, Default, Reflect)]
255
/// #[reflect(Component)]
256
/// struct MyComponent;
257
///
258
/// # let mut world = World::default();
259
/// # world.init_resource::<AppTypeRegistry>();
260
/// # let _entity = world.spawn(MyComponent).id();
261
/// let mut query = world.query_filtered::<Entity, With<MyComponent>>();
262
///
263
/// let scene = DynamicSceneBuilder::from_world(&world)
264
/// .extract_entities(query.iter(&world))
265
/// .build();
266
/// ```
267
///
268
/// Note that components extracted from queried entities must still pass through the filter if one is set.
269
///
270
/// [`allow`]: Self::allow_component
271
/// [`deny`]: Self::deny_component
272
#[must_use]
273
pub fn extract_entities(mut self, entities: impl Iterator<Item = Entity>) -> Self {
274
let type_registry = self.original_world.resource::<AppTypeRegistry>().read();
275
276
for entity in entities {
277
if self.extracted_scene.contains_key(&entity) {
278
continue;
279
}
280
281
let mut entry = DynamicEntity {
282
entity,
283
components: Vec::new(),
284
};
285
286
let original_entity = self.original_world.entity(entity);
287
if original_entity.contains_id(IS_RESOURCE) {
288
continue;
289
}
290
291
for &component_id in original_entity.archetype().components().iter() {
292
let mut extract_and_push = || {
293
let type_id = self
294
.original_world
295
.components()
296
.get_info(component_id)?
297
.type_id()?;
298
299
let is_denied = self.component_filter.is_denied_by_id(type_id);
300
301
if is_denied {
302
// Component is either in the denylist or _not_ in the allowlist
303
return None;
304
}
305
306
let type_registration = type_registry.get(type_id)?;
307
308
let component = type_registration
309
.data::<ReflectComponent>()?
310
.reflect(original_entity)?;
311
312
let component =
313
clone_reflect_value(component.as_partial_reflect(), type_registration);
314
315
entry.components.push(component);
316
Some(())
317
};
318
extract_and_push();
319
}
320
self.extracted_scene.insert(entity, entry);
321
}
322
323
self
324
}
325
326
/// Extract resources from the builder's [`World`].
327
///
328
/// Re-extracting a resource that was already extracted will have no effect.
329
///
330
/// To control which resources are extracted, use the [`allow_resource`] or
331
/// [`deny_resource`] helper methods.
332
///
333
/// ```
334
/// # use bevy_scene::DynamicSceneBuilder;
335
/// # use bevy_ecs::reflect::AppTypeRegistry;
336
/// # use bevy_ecs::prelude::{ReflectResource, Resource, World};
337
/// # use bevy_reflect::Reflect;
338
/// #[derive(Resource, Default, Reflect)]
339
/// #[reflect(Resource)]
340
/// struct MyResource;
341
///
342
/// # let mut world = World::default();
343
/// # world.init_resource::<AppTypeRegistry>();
344
/// world.insert_resource(MyResource);
345
///
346
/// let mut builder = DynamicSceneBuilder::from_world(&world).extract_resources();
347
/// let scene = builder.build();
348
/// ```
349
///
350
/// [`allow_resource`]: Self::allow_resource
351
/// [`deny_resource`]: Self::deny_resource
352
#[must_use]
353
pub fn extract_resources(mut self) -> Self {
354
// Don't extract the DefaultQueryFilters resource
355
let original_world_dqf_id = self
356
.original_world
357
.components()
358
.get_valid_id(TypeId::of::<DefaultQueryFilters>());
359
360
let type_registry = self.original_world.resource::<AppTypeRegistry>().read();
361
362
for (component_id, entity) in self.original_world.resource_entities().iter() {
363
if Some(*component_id) == original_world_dqf_id {
364
continue;
365
}
366
let mut extract_and_push = || {
367
let type_id = self
368
.original_world
369
.components()
370
.get_info(*component_id)?
371
.type_id()?;
372
373
let is_denied = self.resource_filter.is_denied_by_id(type_id);
374
375
if is_denied {
376
// Resource is either in the denylist or _not_ in the allowlist
377
return None;
378
}
379
380
let type_registration = type_registry.get(type_id)?;
381
382
type_registration.data::<ReflectResource>()?;
383
let component = type_registration
384
.data::<ReflectComponent>()?
385
.reflect(self.original_world.entity(*entity))?;
386
387
let component =
388
clone_reflect_value(component.as_partial_reflect(), type_registration);
389
390
self.extracted_resources.insert(*component_id, component);
391
Some(())
392
};
393
extract_and_push();
394
}
395
396
drop(type_registry);
397
self
398
}
399
}
400
401
#[cfg(test)]
402
mod tests {
403
use bevy_ecs::{
404
component::Component,
405
prelude::{Entity, Resource},
406
query::With,
407
reflect::{AppTypeRegistry, ReflectComponent, ReflectResource},
408
world::World,
409
};
410
411
use bevy_reflect::Reflect;
412
413
use super::DynamicSceneBuilder;
414
415
#[derive(Component, Reflect, Default, Eq, PartialEq, Debug)]
416
#[reflect(Component)]
417
struct ComponentA;
418
419
#[derive(Component, Reflect, Default, Eq, PartialEq, Debug)]
420
#[reflect(Component)]
421
struct ComponentB;
422
423
#[derive(Resource, Reflect, Default, Eq, PartialEq, Debug)]
424
#[reflect(Resource)]
425
struct ResourceA;
426
427
#[derive(Resource, Reflect, Default, Eq, PartialEq, Debug)]
428
#[reflect(Resource)]
429
struct ResourceB;
430
431
#[test]
432
fn extract_one_entity() {
433
let mut world = World::default();
434
435
let atr = AppTypeRegistry::default();
436
atr.write().register::<ComponentA>();
437
world.insert_resource(atr);
438
439
let entity = world.spawn((ComponentA, ComponentB)).id();
440
441
let scene = DynamicSceneBuilder::from_world(&world)
442
.extract_entity(entity)
443
.build();
444
445
assert_eq!(scene.entities.len(), 1);
446
assert_eq!(scene.entities[0].entity, entity);
447
assert_eq!(scene.entities[0].components.len(), 1);
448
assert!(scene.entities[0].components[0].represents::<ComponentA>());
449
}
450
451
#[test]
452
fn extract_one_entity_twice() {
453
let mut world = World::default();
454
455
let atr = AppTypeRegistry::default();
456
atr.write().register::<ComponentA>();
457
world.insert_resource(atr);
458
459
let entity = world.spawn((ComponentA, ComponentB)).id();
460
461
let scene = DynamicSceneBuilder::from_world(&world)
462
.extract_entity(entity)
463
.extract_entity(entity)
464
.build();
465
466
assert_eq!(scene.entities.len(), 1);
467
assert_eq!(scene.entities[0].entity, entity);
468
assert_eq!(scene.entities[0].components.len(), 1);
469
assert!(scene.entities[0].components[0].represents::<ComponentA>());
470
}
471
472
#[test]
473
fn extract_one_entity_two_components() {
474
let mut world = World::default();
475
476
let atr = AppTypeRegistry::default();
477
{
478
let mut register = atr.write();
479
register.register::<ComponentA>();
480
register.register::<ComponentB>();
481
}
482
world.insert_resource(atr);
483
484
let entity = world.spawn((ComponentA, ComponentB)).id();
485
486
let scene = DynamicSceneBuilder::from_world(&world)
487
.extract_entity(entity)
488
.build();
489
490
assert_eq!(scene.entities.len(), 1);
491
assert_eq!(scene.entities[0].entity, entity);
492
assert_eq!(scene.entities[0].components.len(), 2);
493
assert!(scene.entities[0].components[0].represents::<ComponentA>());
494
assert!(scene.entities[0].components[1].represents::<ComponentB>());
495
}
496
497
#[test]
498
fn extract_entity_order() {
499
let mut world = World::default();
500
world.init_resource::<AppTypeRegistry>();
501
502
// Spawn entities in order
503
let entity_a = world.spawn_empty().id();
504
let entity_b = world.spawn_empty().id();
505
let entity_c = world.spawn_empty().id();
506
let entity_d = world.spawn_empty().id();
507
508
// Insert entities out of order
509
let builder = DynamicSceneBuilder::from_world(&world)
510
.extract_entity(entity_b)
511
.extract_entities([entity_d, entity_a].into_iter())
512
.extract_entity(entity_c);
513
514
let mut entities = builder.build().entities.into_iter();
515
516
// Assert entities are ordered
517
assert_eq!(entity_d, entities.next().map(|e| e.entity).unwrap());
518
assert_eq!(entity_c, entities.next().map(|e| e.entity).unwrap());
519
assert_eq!(entity_b, entities.next().map(|e| e.entity).unwrap());
520
assert_eq!(entity_a, entities.next().map(|e| e.entity).unwrap());
521
}
522
523
#[test]
524
fn extract_query() {
525
let mut world = World::default();
526
527
let atr = AppTypeRegistry::default();
528
{
529
let mut register = atr.write();
530
register.register::<ComponentA>();
531
register.register::<ComponentB>();
532
}
533
world.insert_resource(atr);
534
535
let entity_a_b = world.spawn((ComponentA, ComponentB)).id();
536
let entity_a = world.spawn(ComponentA).id();
537
let _entity_b = world.spawn(ComponentB).id();
538
539
let mut query = world.query_filtered::<Entity, With<ComponentA>>();
540
let scene = DynamicSceneBuilder::from_world(&world)
541
.extract_entities(query.iter(&world))
542
.build();
543
544
assert_eq!(scene.entities.len(), 2);
545
let mut scene_entities = vec![scene.entities[0].entity, scene.entities[1].entity];
546
scene_entities.sort();
547
assert_eq!(scene_entities, [entity_a, entity_a_b]);
548
}
549
550
#[test]
551
fn remove_componentless_entity() {
552
let mut world = World::default();
553
554
let atr = AppTypeRegistry::default();
555
atr.write().register::<ComponentA>();
556
world.insert_resource(atr);
557
558
let entity_a = world.spawn(ComponentA).id();
559
let entity_b = world.spawn(ComponentB).id();
560
561
let scene = DynamicSceneBuilder::from_world(&world)
562
.extract_entities([entity_a, entity_b].into_iter())
563
.remove_empty_entities()
564
.build();
565
566
assert_eq!(scene.entities.len(), 1);
567
assert_eq!(scene.entities[0].entity, entity_a);
568
}
569
570
#[test]
571
fn extract_one_resource() {
572
let mut world = World::default();
573
574
let atr = AppTypeRegistry::default();
575
atr.write().register::<ResourceA>();
576
world.insert_resource(atr);
577
578
world.insert_resource(ResourceA);
579
580
let scene = DynamicSceneBuilder::from_world(&world)
581
.extract_resources()
582
.build();
583
584
assert_eq!(scene.resources.len(), 1);
585
assert!(scene.resources[0].represents::<ResourceA>());
586
}
587
588
#[test]
589
fn extract_one_resource_twice() {
590
let mut world = World::default();
591
592
let atr = AppTypeRegistry::default();
593
atr.write().register::<ResourceA>();
594
world.insert_resource(atr);
595
596
world.insert_resource(ResourceA);
597
598
let scene = DynamicSceneBuilder::from_world(&world)
599
.extract_resources()
600
.extract_resources()
601
.build();
602
603
assert_eq!(scene.resources.len(), 1);
604
assert!(scene.resources[0].represents::<ResourceA>());
605
}
606
607
#[test]
608
fn should_extract_allowed_components() {
609
let mut world = World::default();
610
611
let atr = AppTypeRegistry::default();
612
{
613
let mut register = atr.write();
614
register.register::<ComponentA>();
615
register.register::<ComponentB>();
616
}
617
world.insert_resource(atr);
618
619
let entity_a_b = world.spawn((ComponentA, ComponentB)).id();
620
let entity_a = world.spawn(ComponentA).id();
621
let entity_b = world.spawn(ComponentB).id();
622
623
let scene = DynamicSceneBuilder::from_world(&world)
624
.allow_component::<ComponentA>()
625
.extract_entities([entity_a_b, entity_a, entity_b].into_iter())
626
.build();
627
628
assert_eq!(scene.entities.len(), 3);
629
assert!(scene.entities[2].components[0].represents::<ComponentA>());
630
assert!(scene.entities[1].components[0].represents::<ComponentA>());
631
assert_eq!(scene.entities[0].components.len(), 0);
632
}
633
634
#[test]
635
fn should_not_extract_denied_components() {
636
let mut world = World::default();
637
638
let atr = AppTypeRegistry::default();
639
{
640
let mut register = atr.write();
641
register.register::<ComponentA>();
642
register.register::<ComponentB>();
643
}
644
world.insert_resource(atr);
645
646
let entity_a_b = world.spawn((ComponentA, ComponentB)).id();
647
let entity_a = world.spawn(ComponentA).id();
648
let entity_b = world.spawn(ComponentB).id();
649
650
let scene = DynamicSceneBuilder::from_world(&world)
651
.deny_component::<ComponentA>()
652
.extract_entities([entity_a_b, entity_a, entity_b].into_iter())
653
.build();
654
655
assert_eq!(scene.entities.len(), 3);
656
assert!(scene.entities[0].components[0].represents::<ComponentB>());
657
assert_eq!(scene.entities[1].components.len(), 0);
658
assert!(scene.entities[2].components[0].represents::<ComponentB>());
659
}
660
661
#[test]
662
fn should_extract_allowed_resources() {
663
let mut world = World::default();
664
665
let atr = AppTypeRegistry::default();
666
{
667
let mut register = atr.write();
668
register.register::<ResourceA>();
669
register.register::<ResourceB>();
670
}
671
world.insert_resource(atr);
672
673
world.insert_resource(ResourceA);
674
world.insert_resource(ResourceB);
675
676
let scene = DynamicSceneBuilder::from_world(&world)
677
.allow_resource::<ResourceA>()
678
.extract_resources()
679
.build();
680
681
assert_eq!(scene.resources.len(), 1);
682
assert!(scene.resources[0].represents::<ResourceA>());
683
}
684
685
#[test]
686
fn should_not_extract_denied_resources() {
687
let mut world = World::default();
688
689
let atr = AppTypeRegistry::default();
690
{
691
let mut register = atr.write();
692
register.register::<ResourceA>();
693
register.register::<ResourceB>();
694
}
695
world.insert_resource(atr);
696
697
world.insert_resource(ResourceA);
698
world.insert_resource(ResourceB);
699
700
let scene = DynamicSceneBuilder::from_world(&world)
701
.deny_resource::<ResourceA>()
702
.extract_resources()
703
.build();
704
705
assert_eq!(scene.resources.len(), 1);
706
assert!(scene.resources[0].represents::<ResourceB>());
707
}
708
709
#[test]
710
fn should_use_from_reflect() {
711
#[derive(Component, Reflect)]
712
#[reflect(Component)]
713
struct SomeType(i32);
714
715
#[derive(Resource, Reflect)]
716
#[reflect(Resource)]
717
struct SomeResource(i32);
718
719
let mut world = World::default();
720
let atr = AppTypeRegistry::default();
721
{
722
let mut register = atr.write();
723
register.register::<SomeType>();
724
register.register::<SomeResource>();
725
}
726
world.insert_resource(atr);
727
728
world.insert_resource(SomeResource(123));
729
let entity = world.spawn(SomeType(123)).id();
730
731
let scene = DynamicSceneBuilder::from_world(&world)
732
.extract_resources()
733
.extract_entities(vec![entity].into_iter())
734
.build();
735
736
let component = &scene.entities[0].components[0];
737
assert!(component
738
.try_as_reflect()
739
.expect("component should be concrete due to `FromReflect`")
740
.is::<SomeType>());
741
742
let resource = &scene.resources[0];
743
assert!(resource
744
.try_as_reflect()
745
.expect("resource should be concrete due to `FromReflect`")
746
.is::<SomeResource>());
747
}
748
}
749
750