bevy_ecs/entity/
map_entities.rs

1pub use bevy_ecs_macros::MapEntities;
2
3use crate::{
4    entity::{hash_map::EntityHashMap, Entity},
5    identifier::masks::{IdentifierMask, HIGH_MASK},
6    world::World,
7};
8
9use alloc::{collections::VecDeque, vec::Vec};
10use bevy_platform::collections::HashSet;
11use core::hash::BuildHasher;
12use smallvec::SmallVec;
13
14/// Operation to map all contained [`Entity`] fields in a type to new values.
15///
16/// As entity IDs are valid only for the [`World`] they're sourced from, using [`Entity`]
17/// as references in components copied from another world will be invalid. This trait
18/// allows defining custom mappings for these references via [`EntityMappers`](EntityMapper), which
19/// inject the entity mapping strategy between your `MapEntities` type and the current world
20/// (usually by using an [`EntityHashMap<Entity>`] between source entities and entities in the
21/// current world).
22///
23/// Components use [`Component::map_entities`](crate::component::Component::map_entities) to map
24/// entities in the context of scenes and entity cloning, which generally uses [`MapEntities`] internally
25/// to map each field (see those docs for usage).
26///
27/// [`HashSet<Entity>`]: bevy_platform::collections::HashSet
28///
29/// ## Example
30///
31/// ```
32/// use bevy_ecs::prelude::*;
33/// use bevy_ecs::entity::MapEntities;
34///
35/// #[derive(Component)]
36/// struct Spring {
37///     a: Entity,
38///     b: Entity,
39/// }
40///
41/// impl MapEntities for Spring {
42///     fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
43///         self.a = entity_mapper.get_mapped(self.a);
44///         self.b = entity_mapper.get_mapped(self.b);
45///     }
46/// }
47/// ```
48pub trait MapEntities {
49    /// Updates all [`Entity`] references stored inside using `entity_mapper`.
50    ///
51    /// Implementors should look up any and all [`Entity`] values stored within `self` and
52    /// update them to the mapped values via `entity_mapper`.
53    fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E);
54}
55
56impl MapEntities for Entity {
57    fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
58        *self = entity_mapper.get_mapped(*self);
59    }
60}
61
62impl MapEntities for Option<Entity> {
63    fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
64        if let Some(entity) = self {
65            *entity = entity_mapper.get_mapped(*entity);
66        }
67    }
68}
69
70impl<S: BuildHasher + Default> MapEntities for HashSet<Entity, S> {
71    fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
72        *self = self.drain().map(|e| entity_mapper.get_mapped(e)).collect();
73    }
74}
75impl MapEntities for Vec<Entity> {
76    fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
77        for entity in self.iter_mut() {
78            *entity = entity_mapper.get_mapped(*entity);
79        }
80    }
81}
82
83impl MapEntities for VecDeque<Entity> {
84    fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
85        for entity in self.iter_mut() {
86            *entity = entity_mapper.get_mapped(*entity);
87        }
88    }
89}
90
91impl<A: smallvec::Array<Item = Entity>> MapEntities for SmallVec<A> {
92    fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
93        for entity in self.iter_mut() {
94            *entity = entity_mapper.get_mapped(*entity);
95        }
96    }
97}
98/// An implementor of this trait knows how to map an [`Entity`] into another [`Entity`].
99///
100/// Usually this is done by using an [`EntityHashMap<Entity>`] to map source entities
101/// (mapper inputs) to the current world's entities (mapper outputs).
102///
103/// More generally, this can be used to map [`Entity`] references between any two [`Worlds`](World).
104///
105/// This is used by [`MapEntities`] implementors.
106///
107/// ## Example
108///
109/// ```
110/// # use bevy_ecs::entity::{Entity, EntityMapper};
111/// # use bevy_ecs::entity::EntityHashMap;
112/// #
113/// pub struct SimpleEntityMapper {
114///   map: EntityHashMap<Entity>,
115/// }
116///
117/// // Example implementation of EntityMapper where we map an entity to another entity if it exists
118/// // in the underlying `EntityHashMap`, otherwise we just return the original entity.
119/// impl EntityMapper for SimpleEntityMapper {
120///     fn get_mapped(&mut self, entity: Entity) -> Entity {
121///         self.map.get(&entity).copied().unwrap_or(entity)
122///     }
123///     
124///     fn set_mapped(&mut self, source: Entity, target: Entity) {
125///         self.map.insert(source, target);
126///     }
127/// }
128/// ```
129pub trait EntityMapper {
130    /// Returns the "target" entity that maps to the given `source`.
131    fn get_mapped(&mut self, source: Entity) -> Entity;
132
133    /// Maps the `target` entity to the given `source`. For some implementations this might not actually determine the result
134    /// of [`EntityMapper::get_mapped`].
135    fn set_mapped(&mut self, source: Entity, target: Entity);
136}
137
138impl EntityMapper for () {
139    #[inline]
140    fn get_mapped(&mut self, source: Entity) -> Entity {
141        source
142    }
143
144    #[inline]
145    fn set_mapped(&mut self, _source: Entity, _target: Entity) {}
146}
147
148impl EntityMapper for (Entity, Entity) {
149    #[inline]
150    fn get_mapped(&mut self, source: Entity) -> Entity {
151        if source == self.0 {
152            self.1
153        } else {
154            source
155        }
156    }
157
158    fn set_mapped(&mut self, _source: Entity, _target: Entity) {}
159}
160
161impl EntityMapper for &mut dyn EntityMapper {
162    fn get_mapped(&mut self, source: Entity) -> Entity {
163        (*self).get_mapped(source)
164    }
165
166    fn set_mapped(&mut self, source: Entity, target: Entity) {
167        (*self).set_mapped(source, target);
168    }
169}
170
171impl EntityMapper for SceneEntityMapper<'_> {
172    /// Returns the corresponding mapped entity or reserves a new dead entity ID in the current world if it is absent.
173    fn get_mapped(&mut self, source: Entity) -> Entity {
174        if let Some(&mapped) = self.map.get(&source) {
175            return mapped;
176        }
177
178        // this new entity reference is specifically designed to never represent any living entity
179        let new = Entity::from_raw_and_generation(
180            self.dead_start.index(),
181            IdentifierMask::inc_masked_high_by(self.dead_start.generation, self.generations),
182        );
183
184        // Prevent generations counter from being a greater value than HIGH_MASK.
185        self.generations = (self.generations + 1) & HIGH_MASK;
186
187        self.map.insert(source, new);
188
189        new
190    }
191
192    fn set_mapped(&mut self, source: Entity, target: Entity) {
193        self.map.insert(source, target);
194    }
195}
196
197impl EntityMapper for EntityHashMap<Entity> {
198    /// Returns the corresponding mapped entity or returns `entity` if there is no mapped entity
199    fn get_mapped(&mut self, source: Entity) -> Entity {
200        self.get(&source).cloned().unwrap_or(source)
201    }
202
203    fn set_mapped(&mut self, source: Entity, target: Entity) {
204        self.insert(source, target);
205    }
206}
207
208/// A wrapper for [`EntityHashMap<Entity>`], augmenting it with the ability to allocate new [`Entity`] references in a destination
209/// world. These newly allocated references are guaranteed to never point to any living entity in that world.
210///
211/// References are allocated by returning increasing generations starting from an internally initialized base
212/// [`Entity`]. After it is finished being used, this entity is despawned and the requisite number of generations reserved.
213pub struct SceneEntityMapper<'m> {
214    /// A mapping from one set of entities to another.
215    ///
216    /// This is typically used to coordinate data transfer between sets of entities, such as between a scene and the world
217    /// or over the network. This is required as [`Entity`] identifiers are opaque; you cannot and do not want to reuse
218    /// identifiers directly.
219    ///
220    /// On its own, a [`EntityHashMap<Entity>`] is not capable of allocating new entity identifiers, which is needed to map references
221    /// to entities that lie outside the source entity set. This functionality can be accessed through [`SceneEntityMapper::world_scope()`].
222    map: &'m mut EntityHashMap<Entity>,
223    /// A base [`Entity`] used to allocate new references.
224    dead_start: Entity,
225    /// The number of generations this mapper has allocated thus far.
226    generations: u32,
227}
228
229impl<'m> SceneEntityMapper<'m> {
230    /// Gets a reference to the underlying [`EntityHashMap<Entity>`].
231    pub fn get_map(&'m self) -> &'m EntityHashMap<Entity> {
232        self.map
233    }
234
235    /// Gets a mutable reference to the underlying [`EntityHashMap<Entity>`].
236    pub fn get_map_mut(&'m mut self) -> &'m mut EntityHashMap<Entity> {
237        self.map
238    }
239
240    /// Creates a new [`SceneEntityMapper`], spawning a temporary base [`Entity`] in the provided [`World`]
241    pub fn new(map: &'m mut EntityHashMap<Entity>, world: &mut World) -> Self {
242        // We're going to be calling methods on `Entities` that require advance
243        // flushing, such as `alloc` and `free`.
244        world.flush_entities();
245        Self {
246            map,
247            // SAFETY: Entities data is kept in a valid state via `EntityMapper::world_scope`
248            dead_start: unsafe { world.entities_mut().alloc() },
249            generations: 0,
250        }
251    }
252
253    /// Reserves the allocated references to dead entities within the world. This frees the temporary base
254    /// [`Entity`] while reserving extra generations. Because this makes the [`SceneEntityMapper`] unable to
255    /// safely allocate any more references, this method takes ownership of `self` in order to render it unusable.
256    pub fn finish(self, world: &mut World) {
257        // SAFETY: Entities data is kept in a valid state via `EntityMap::world_scope`
258        let entities = unsafe { world.entities_mut() };
259        assert!(entities.free(self.dead_start).is_some());
260        assert!(entities.reserve_generations(self.dead_start.index(), self.generations));
261    }
262
263    /// Creates an [`SceneEntityMapper`] from a provided [`World`] and [`EntityHashMap<Entity>`], then calls the
264    /// provided function with it. This allows one to allocate new entity references in this [`World`] that are
265    /// guaranteed to never point at a living entity now or in the future. This functionality is useful for safely
266    /// mapping entity identifiers that point at entities outside the source world. The passed function, `f`, is called
267    /// within the scope of this world. Its return value is then returned from `world_scope` as the generic type
268    /// parameter `R`.
269    pub fn world_scope<R>(
270        entity_map: &'m mut EntityHashMap<Entity>,
271        world: &mut World,
272        f: impl FnOnce(&mut World, &mut Self) -> R,
273    ) -> R {
274        let mut mapper = Self::new(entity_map, world);
275        let result = f(world, &mut mapper);
276        mapper.finish(world);
277        result
278    }
279}
280
281#[cfg(test)]
282mod tests {
283    use crate::{
284        entity::{Entity, EntityHashMap, EntityMapper, SceneEntityMapper},
285        world::World,
286    };
287
288    #[test]
289    fn entity_mapper() {
290        const FIRST_IDX: u32 = 1;
291        const SECOND_IDX: u32 = 2;
292
293        let mut map = EntityHashMap::default();
294        let mut world = World::new();
295        let mut mapper = SceneEntityMapper::new(&mut map, &mut world);
296
297        let mapped_ent = Entity::from_raw(FIRST_IDX);
298        let dead_ref = mapper.get_mapped(mapped_ent);
299
300        assert_eq!(
301            dead_ref,
302            mapper.get_mapped(mapped_ent),
303            "should persist the allocated mapping from the previous line"
304        );
305        assert_eq!(
306            mapper.get_mapped(Entity::from_raw(SECOND_IDX)).index(),
307            dead_ref.index(),
308            "should re-use the same index for further dead refs"
309        );
310
311        mapper.finish(&mut world);
312        // Next allocated entity should be a further generation on the same index
313        let entity = world.spawn_empty().id();
314        assert_eq!(entity.index(), dead_ref.index());
315        assert!(entity.generation() > dead_ref.generation());
316    }
317
318    #[test]
319    fn world_scope_reserves_generations() {
320        let mut map = EntityHashMap::default();
321        let mut world = World::new();
322
323        let dead_ref = SceneEntityMapper::world_scope(&mut map, &mut world, |_, mapper| {
324            mapper.get_mapped(Entity::from_raw(0))
325        });
326
327        // Next allocated entity should be a further generation on the same index
328        let entity = world.spawn_empty().id();
329        assert_eq!(entity.index(), dead_ref.index());
330        assert!(entity.generation() > dead_ref.generation());
331    }
332
333    #[test]
334    fn entity_mapper_no_panic() {
335        let mut world = World::new();
336        // "Dirty" the `Entities`, requiring a flush afterward.
337        world.entities.reserve_entity();
338        assert!(world.entities.needs_flush());
339
340        // Create and exercise a SceneEntityMapper - should not panic because it flushes
341        // `Entities` first.
342        SceneEntityMapper::world_scope(&mut Default::default(), &mut world, |_, m| {
343            m.get_mapped(Entity::PLACEHOLDER);
344        });
345
346        // The SceneEntityMapper should leave `Entities` in a flushed state.
347        assert!(!world.entities.needs_flush());
348    }
349}