bevy_ecs/reflect/map_entities.rs
1use crate::{
2 component::Component,
3 entity::{Entity, EntityHashMap, MapEntities, SceneEntityMapper},
4 world::World,
5};
6use bevy_reflect::FromType;
7
8/// For a specific type of component, this maps any fields with values of type [`Entity`] to a new world.
9/// Since a given `Entity` ID is only valid for the world it came from, when performing deserialization
10/// any stored IDs need to be re-allocated in the destination world.
11///
12/// See [`SceneEntityMapper`] and [`MapEntities`] for more information.
13#[derive(Clone)]
14pub struct ReflectMapEntities {
15 map_all_entities: fn(&mut World, &mut SceneEntityMapper),
16 map_entities: fn(&mut World, &mut SceneEntityMapper, &[Entity]),
17}
18
19impl ReflectMapEntities {
20 /// A general method for applying [`MapEntities`] behavior to all elements in an [`EntityHashMap<Entity>`].
21 ///
22 /// Be mindful in its usage: Works best in situations where the entities in the [`EntityHashMap<Entity>`] are newly
23 /// created, before systems have a chance to add new components. If some of the entities referred to
24 /// by the [`EntityHashMap<Entity>`] might already contain valid entity references, you should use [`map_entities`](Self::map_entities).
25 ///
26 /// An example of this: A scene can be loaded with `Parent` components, but then a `Parent` component can be added
27 /// to these entities after they have been loaded. If you reload the scene using [`map_all_entities`](Self::map_all_entities), those `Parent`
28 /// components with already valid entity references could be updated to point at something else entirely.
29 pub fn map_all_entities(&self, world: &mut World, entity_map: &mut EntityHashMap<Entity>) {
30 SceneEntityMapper::world_scope(entity_map, world, self.map_all_entities);
31 }
32
33 /// A general method for applying [`MapEntities`] behavior to elements in an [`EntityHashMap<Entity>`]. Unlike
34 /// [`map_all_entities`](Self::map_all_entities), this is applied to specific entities, not all values
35 /// in the [`EntityHashMap<Entity>`].
36 ///
37 /// This is useful mostly for when you need to be careful not to update components that already contain valid entity
38 /// values. See [`map_all_entities`](Self::map_all_entities) for more details.
39 pub fn map_entities(
40 &self,
41 world: &mut World,
42 entity_map: &mut EntityHashMap<Entity>,
43 entities: &[Entity],
44 ) {
45 SceneEntityMapper::world_scope(entity_map, world, |world, mapper| {
46 (self.map_entities)(world, mapper, entities);
47 });
48 }
49}
50
51impl<C: Component + MapEntities> FromType<C> for ReflectMapEntities {
52 fn from_type() -> Self {
53 ReflectMapEntities {
54 map_entities: |world, entity_mapper, entities| {
55 for &entity in entities {
56 if let Some(mut component) = world.get_mut::<C>(entity) {
57 component.map_entities(entity_mapper);
58 }
59 }
60 },
61 map_all_entities: |world, entity_mapper| {
62 let entities = entity_mapper
63 .get_map()
64 .values()
65 .copied()
66 .collect::<Vec<Entity>>();
67 for entity in &entities {
68 if let Some(mut component) = world.get_mut::<C>(*entity) {
69 component.map_entities(entity_mapper);
70 }
71 }
72 },
73 }
74 }
75}
76
77/// For a specific type of resource, this maps any fields with values of type [`Entity`] to a new world.
78/// Since a given `Entity` ID is only valid for the world it came from, when performing deserialization
79/// any stored IDs need to be re-allocated in the destination world.
80///
81/// See [`SceneEntityMapper`] and [`MapEntities`] for more information.
82#[derive(Clone)]
83pub struct ReflectMapEntitiesResource {
84 map_entities: fn(&mut World, &mut SceneEntityMapper),
85}
86
87impl ReflectMapEntitiesResource {
88 /// A method for applying [`MapEntities`] behavior to elements in an [`EntityHashMap<Entity>`].
89 pub fn map_entities(&self, world: &mut World, entity_map: &mut EntityHashMap<Entity>) {
90 SceneEntityMapper::world_scope(entity_map, world, |world, mapper| {
91 (self.map_entities)(world, mapper);
92 });
93 }
94}
95
96impl<R: crate::system::Resource + MapEntities> FromType<R> for ReflectMapEntitiesResource {
97 fn from_type() -> Self {
98 ReflectMapEntitiesResource {
99 map_entities: |world, entity_mapper| {
100 if let Some(mut resource) = world.get_resource_mut::<R>() {
101 resource.map_entities(entity_mapper);
102 }
103 },
104 }
105 }
106}