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}