-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
/
dynamic_scene.rs
147 lines (131 loc) · 6.02 KB
/
dynamic_scene.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
use crate::{serde::SceneSerializer, Scene, SceneSpawnError};
use anyhow::Result;
use bevy_app::AppTypeRegistry;
use bevy_ecs::{
entity::EntityMap,
reflect::{ReflectComponent, ReflectMapEntities},
world::World,
};
use bevy_reflect::{Reflect, TypeRegistryArc, TypeUuid};
use serde::Serialize;
/// A collection of serializable dynamic entities, each with its own run-time defined set of components.
/// To spawn a dynamic scene, you can use either:
/// * [`SceneSpawner::spawn_dynamic`](crate::SceneSpawner::spawn_dynamic)
/// * adding the [`DynamicSceneBundle`](crate::DynamicSceneBundle) to an entity
/// * adding the [`Handle<DynamicScene>`](bevy_asset::Handle) to an entity (the scene will only be
/// visible if the entity already has [`Transform`](bevy_transform::components::Transform) and
/// [`GlobalTransform`](bevy_transform::components::GlobalTransform) components)
#[derive(Default, TypeUuid)]
#[uuid = "749479b1-fb8c-4ff8-a775-623aa76014f5"]
pub struct DynamicScene {
pub entities: Vec<DynamicEntity>,
}
/// A reflection-powered serializable representation of an entity and its components.
pub struct DynamicEntity {
/// The transiently unique identifier of a corresponding `Entity`.
pub entity: u32,
/// A vector of boxed components that belong to the given entity and
/// implement the `Reflect` trait.
pub components: Vec<Box<dyn Reflect>>,
}
impl DynamicScene {
/// Create a new dynamic scene from a given scene.
pub fn from_scene(scene: &Scene, type_registry: &TypeRegistryArc) -> Self {
Self::from_world(&scene.world, type_registry)
}
/// Create a new dynamic scene from a given world.
pub fn from_world(world: &World, type_registry: &TypeRegistryArc) -> Self {
let mut scene = DynamicScene::default();
let type_registry = type_registry.read();
for archetype in world.archetypes().iter() {
let entities_offset = scene.entities.len();
// Create a new dynamic entity for each entity of the given archetype
// and insert it into the dynamic scene.
for entity in archetype.entities() {
scene.entities.push(DynamicEntity {
entity: entity.id(),
components: Vec::new(),
});
}
// Add each reflection-powered component to the entity it belongs to.
for component_id in archetype.components() {
let reflect_component = world
.components()
.get_info(component_id)
.and_then(|info| type_registry.get(info.type_id().unwrap()))
.and_then(|registration| registration.data::<ReflectComponent>());
if let Some(reflect_component) = reflect_component {
for (i, entity) in archetype.entities().iter().enumerate() {
if let Some(component) = reflect_component.reflect(world, *entity) {
scene.entities[entities_offset + i]
.components
.push(component.clone_value());
}
}
}
}
}
scene
}
/// Write the dynamic entities and their corresponding components to the given world.
///
/// This method will return a [`SceneSpawnError`] if a type either is not registered
/// or doesn't reflect the [`Component`](bevy_ecs::component::Component) trait.
pub fn write_to_world(
&self,
world: &mut World,
entity_map: &mut EntityMap,
) -> Result<(), SceneSpawnError> {
let registry = world.resource::<AppTypeRegistry>().clone();
let type_registry = registry.read();
for scene_entity in &self.entities {
// Fetch the entity with the given entity id from the `entity_map`
// or spawn a new entity with a transiently unique id if there is
// no corresponding entry.
let entity = *entity_map
.entry(bevy_ecs::entity::Entity::from_raw(scene_entity.entity))
.or_insert_with(|| world.spawn().id());
// Apply/ add each component to the given entity.
for component in &scene_entity.components {
let registration = type_registry
.get_with_name(component.type_name())
.ok_or_else(|| SceneSpawnError::UnregisteredType {
type_name: component.type_name().to_string(),
})?;
let reflect_component =
registration.data::<ReflectComponent>().ok_or_else(|| {
SceneSpawnError::UnregisteredComponent {
type_name: component.type_name().to_string(),
}
})?;
// If the entity already has the given component attached,
// just apply the (possibly) new value, otherwise add the
// component to the entity.
reflect_component.apply_or_insert(world, entity, &**component);
}
}
for registration in type_registry.iter() {
if let Some(map_entities_reflect) = registration.data::<ReflectMapEntities>() {
map_entities_reflect
.map_entities(world, entity_map)
.unwrap();
}
}
Ok(())
}
// TODO: move to AssetSaver when it is implemented
/// Serialize this dynamic scene into rust object notation (ron).
pub fn serialize_ron(&self, registry: &TypeRegistryArc) -> Result<String, ron::Error> {
serialize_ron(SceneSerializer::new(self, registry))
}
}
/// Serialize a given Rust data structure into rust object notation (ron).
pub fn serialize_ron<S>(serialize: S) -> Result<String, ron::Error>
where
S: Serialize,
{
let pretty_config = ron::ser::PrettyConfig::default()
.indentor(" ".to_string())
.new_line("\n".to_string());
ron::ser::to_string_pretty(&serialize, pretty_config)
}