bevy_ecs/entity/
map_entities.rs

1use crate::{
2    entity::Entity,
3    identifier::masks::{IdentifierMask, HIGH_MASK},
4    world::World,
5};
6
7use super::{EntityHashMap, VisitEntitiesMut};
8
9/// Operation to map all contained [`Entity`] fields in a type to new values.
10///
11/// As entity IDs are valid only for the [`World`] they're sourced from, using [`Entity`]
12/// as references in components copied from another world will be invalid. This trait
13/// allows defining custom mappings for these references via [`EntityMappers`](EntityMapper), which
14/// inject the entity mapping strategy between your `MapEntities` type and the current world
15/// (usually by using an [`EntityHashMap<Entity>`] between source entities and entities in the
16/// current world).
17///
18/// This trait is similar to [`VisitEntitiesMut`]. They differ in that [`VisitEntitiesMut`] operates
19/// on `&mut Entity` and allows for in-place modification, while this trait makes no assumption that
20/// such in-place modification is occurring, which is impossible for types such as [`HashSet<Entity>`]
21/// and [`EntityHashMap`] which must be rebuilt when their contained [`Entity`]s are remapped.
22///
23/// Implementing this trait correctly is required for properly loading components
24/// with entity references from scenes.
25///
26/// [`HashSet<Entity>`]: bevy_utils::HashSet
27///
28/// ## Example
29///
30/// ```
31/// use bevy_ecs::prelude::*;
32/// use bevy_ecs::entity::MapEntities;
33///
34/// #[derive(Component)]
35/// struct Spring {
36///     a: Entity,
37///     b: Entity,
38/// }
39///
40/// impl MapEntities for Spring {
41///     fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
42///         self.a = entity_mapper.map_entity(self.a);
43///         self.b = entity_mapper.map_entity(self.b);
44///     }
45/// }
46/// ```
47pub trait MapEntities {
48    /// Updates all [`Entity`] references stored inside using `entity_mapper`.
49    ///
50    /// Implementors should look up any and all [`Entity`] values stored within `self` and
51    /// update them to the mapped values via `entity_mapper`.
52    fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M);
53}
54
55impl<T: VisitEntitiesMut> MapEntities for T {
56    fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
57        self.visit_entities_mut(|entity| {
58            *entity = entity_mapper.map_entity(*entity);
59        });
60    }
61}
62
63/// An implementor of this trait knows how to map an [`Entity`] into another [`Entity`].
64///
65/// Usually this is done by using an [`EntityHashMap<Entity>`] to map source entities
66/// (mapper inputs) to the current world's entities (mapper outputs).
67///
68/// More generally, this can be used to map [`Entity`] references between any two [`Worlds`](World).
69///
70/// ## Example
71///
72/// ```
73/// # use bevy_ecs::entity::{Entity, EntityMapper};
74/// # use bevy_ecs::entity::EntityHashMap;
75/// #
76/// pub struct SimpleEntityMapper {
77///   map: EntityHashMap<Entity>,
78/// }
79///
80/// // Example implementation of EntityMapper where we map an entity to another entity if it exists
81/// // in the underlying `EntityHashMap`, otherwise we just return the original entity.
82/// impl EntityMapper for SimpleEntityMapper {
83///     fn map_entity(&mut self, entity: Entity) -> Entity {
84///         self.map.get(&entity).copied().unwrap_or(entity)
85///     }
86/// }
87/// ```
88pub trait EntityMapper {
89    /// Map an entity to another entity
90    fn map_entity(&mut self, entity: Entity) -> Entity;
91}
92
93impl EntityMapper for &mut dyn EntityMapper {
94    fn map_entity(&mut self, entity: Entity) -> Entity {
95        (*self).map_entity(entity)
96    }
97}
98
99impl EntityMapper for SceneEntityMapper<'_> {
100    /// Returns the corresponding mapped entity or reserves a new dead entity ID in the current world if it is absent.
101    fn map_entity(&mut self, entity: Entity) -> Entity {
102        if let Some(&mapped) = self.map.get(&entity) {
103            return mapped;
104        }
105
106        // this new entity reference is specifically designed to never represent any living entity
107        let new = Entity::from_raw_and_generation(
108            self.dead_start.index(),
109            IdentifierMask::inc_masked_high_by(self.dead_start.generation, self.generations),
110        );
111
112        // Prevent generations counter from being a greater value than HIGH_MASK.
113        self.generations = (self.generations + 1) & HIGH_MASK;
114
115        self.map.insert(entity, new);
116
117        new
118    }
119}
120
121/// A wrapper for [`EntityHashMap<Entity>`], augmenting it with the ability to allocate new [`Entity`] references in a destination
122/// world. These newly allocated references are guaranteed to never point to any living entity in that world.
123///
124/// References are allocated by returning increasing generations starting from an internally initialized base
125/// [`Entity`]. After it is finished being used, this entity is despawned and the requisite number of generations reserved.
126pub struct SceneEntityMapper<'m> {
127    /// A mapping from one set of entities to another.
128    ///
129    /// This is typically used to coordinate data transfer between sets of entities, such as between a scene and the world
130    /// or over the network. This is required as [`Entity`] identifiers are opaque; you cannot and do not want to reuse
131    /// identifiers directly.
132    ///
133    /// On its own, a [`EntityHashMap<Entity>`] is not capable of allocating new entity identifiers, which is needed to map references
134    /// to entities that lie outside the source entity set. This functionality can be accessed through [`SceneEntityMapper::world_scope()`].
135    map: &'m mut EntityHashMap<Entity>,
136    /// A base [`Entity`] used to allocate new references.
137    dead_start: Entity,
138    /// The number of generations this mapper has allocated thus far.
139    generations: u32,
140}
141
142impl<'m> SceneEntityMapper<'m> {
143    /// Gets a reference to the underlying [`EntityHashMap<Entity>`].
144    pub fn get_map(&'m self) -> &'m EntityHashMap<Entity> {
145        self.map
146    }
147
148    /// Gets a mutable reference to the underlying [`EntityHashMap<Entity>`].
149    pub fn get_map_mut(&'m mut self) -> &'m mut EntityHashMap<Entity> {
150        self.map
151    }
152
153    /// Creates a new [`SceneEntityMapper`], spawning a temporary base [`Entity`] in the provided [`World`]
154    pub fn new(map: &'m mut EntityHashMap<Entity>, world: &mut World) -> Self {
155        // We're going to be calling methods on `Entities` that require advance
156        // flushing, such as `alloc` and `free`.
157        world.flush_entities();
158        Self {
159            map,
160            // SAFETY: Entities data is kept in a valid state via `EntityMapper::world_scope`
161            dead_start: unsafe { world.entities_mut().alloc() },
162            generations: 0,
163        }
164    }
165
166    /// Reserves the allocated references to dead entities within the world. This frees the temporary base
167    /// [`Entity`] while reserving extra generations. Because this makes the [`SceneEntityMapper`] unable to
168    /// safely allocate any more references, this method takes ownership of `self` in order to render it unusable.
169    pub fn finish(self, world: &mut World) {
170        // SAFETY: Entities data is kept in a valid state via `EntityMap::world_scope`
171        let entities = unsafe { world.entities_mut() };
172        assert!(entities.free(self.dead_start).is_some());
173        assert!(entities.reserve_generations(self.dead_start.index(), self.generations));
174    }
175
176    /// Creates an [`SceneEntityMapper`] from a provided [`World`] and [`EntityHashMap<Entity>`], then calls the
177    /// provided function with it. This allows one to allocate new entity references in this [`World`] that are
178    /// guaranteed to never point at a living entity now or in the future. This functionality is useful for safely
179    /// mapping entity identifiers that point at entities outside the source world. The passed function, `f`, is called
180    /// within the scope of this world. Its return value is then returned from `world_scope` as the generic type
181    /// parameter `R`.
182    pub fn world_scope<R>(
183        entity_map: &'m mut EntityHashMap<Entity>,
184        world: &mut World,
185        f: impl FnOnce(&mut World, &mut Self) -> R,
186    ) -> R {
187        let mut mapper = Self::new(entity_map, world);
188        let result = f(world, &mut mapper);
189        mapper.finish(world);
190        result
191    }
192}
193
194#[cfg(test)]
195mod tests {
196    use crate::{
197        entity::{Entity, EntityHashMap, EntityMapper, SceneEntityMapper},
198        world::World,
199    };
200
201    #[test]
202    fn entity_mapper() {
203        const FIRST_IDX: u32 = 1;
204        const SECOND_IDX: u32 = 2;
205
206        let mut map = EntityHashMap::default();
207        let mut world = World::new();
208        let mut mapper = SceneEntityMapper::new(&mut map, &mut world);
209
210        let mapped_ent = Entity::from_raw(FIRST_IDX);
211        let dead_ref = mapper.map_entity(mapped_ent);
212
213        assert_eq!(
214            dead_ref,
215            mapper.map_entity(mapped_ent),
216            "should persist the allocated mapping from the previous line"
217        );
218        assert_eq!(
219            mapper.map_entity(Entity::from_raw(SECOND_IDX)).index(),
220            dead_ref.index(),
221            "should re-use the same index for further dead refs"
222        );
223
224        mapper.finish(&mut world);
225        // Next allocated entity should be a further generation on the same index
226        let entity = world.spawn_empty().id();
227        assert_eq!(entity.index(), dead_ref.index());
228        assert!(entity.generation() > dead_ref.generation());
229    }
230
231    #[test]
232    fn world_scope_reserves_generations() {
233        let mut map = EntityHashMap::default();
234        let mut world = World::new();
235
236        let dead_ref = SceneEntityMapper::world_scope(&mut map, &mut world, |_, mapper| {
237            mapper.map_entity(Entity::from_raw(0))
238        });
239
240        // Next allocated entity should be a further generation on the same index
241        let entity = world.spawn_empty().id();
242        assert_eq!(entity.index(), dead_ref.index());
243        assert!(entity.generation() > dead_ref.generation());
244    }
245
246    #[test]
247    fn entity_mapper_no_panic() {
248        let mut world = World::new();
249        // "Dirty" the `Entities`, requiring a flush afterward.
250        world.entities.reserve_entity();
251        assert!(world.entities.needs_flush());
252
253        // Create and exercise a SceneEntityMapper - should not panic because it flushes
254        // `Entities` first.
255        SceneEntityMapper::world_scope(&mut Default::default(), &mut world, |_, m| {
256            m.map_entity(Entity::PLACEHOLDER);
257        });
258
259        // The SceneEntityMapper should leave `Entities` in a flushed state.
260        assert!(!world.entities.needs_flush());
261    }
262}