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