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