1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
use crate::entity::Entity;
use bevy_utils::{Entry, HashMap};
use std::fmt;
/// The errors that might be returned while using [`MapEntities::map_entities`].
#[derive(Debug)]
pub enum MapEntitiesError {
EntityNotFound(Entity),
}
impl std::error::Error for MapEntitiesError {}
impl fmt::Display for MapEntitiesError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
MapEntitiesError::EntityNotFound(_) => {
write!(f, "the given entity does not exist in the map")
}
}
}
}
/// Operation to map all contained [`Entity`] fields in a type to new values.
///
/// As entity IDs are valid only for the [`World`] they're sourced from, using [`Entity`]
/// as references in components copied from another world will be invalid. This trait
/// allows defining custom mappings for these references via [`EntityMap`].
///
/// Implementing this trait correctly is required for properly loading components
/// with entity references from scenes.
///
/// ## Example
///
/// ```rust
/// use bevy_ecs::prelude::*;
/// use bevy_ecs::entity::{EntityMap, MapEntities, MapEntitiesError};
///
/// #[derive(Component)]
/// struct Spring {
/// a: Entity,
/// b: Entity,
/// }
///
/// impl MapEntities for Spring {
/// fn map_entities(&mut self, entity_map: &EntityMap) -> Result<(), MapEntitiesError> {
/// self.a = entity_map.get(self.a)?;
/// self.b = entity_map.get(self.b)?;
/// Ok(())
/// }
/// }
/// ```
///
/// [`World`]: crate::world::World
pub trait MapEntities {
/// Updates all [`Entity`] references stored inside using `entity_map`.
///
/// Implementors should look up any and all [`Entity`] values stored within and
/// update them to the mapped values via `entity_map`.
fn map_entities(&mut self, entity_map: &EntityMap) -> Result<(), MapEntitiesError>;
}
/// A mapping from one set of entities to another.
///
/// The API generally follows [`HashMap`], but each [`Entity`] is returned by value, as they are [`Copy`].
///
/// This is typically used to coordinate data transfer between sets of entities, such as between a scene and the world or over the network.
/// This is required as [`Entity`] identifiers are opaque; you cannot and do not want to reuse identifiers directly.
#[derive(Default, Debug)]
pub struct EntityMap {
map: HashMap<Entity, Entity>,
}
impl EntityMap {
/// Inserts an entities pair into the map.
///
/// If the map did not have `from` present, [`None`] is returned.
///
/// If the map did have `from` present, the value is updated, and the old value is returned.
pub fn insert(&mut self, from: Entity, to: Entity) -> Option<Entity> {
self.map.insert(from, to)
}
/// Removes an `entity` from the map, returning the mapped value of it if the `entity` was previously in the map.
pub fn remove(&mut self, entity: Entity) -> Option<Entity> {
self.map.remove(&entity)
}
/// Gets the given entity's corresponding entry in the map for in-place manipulation.
pub fn entry(&mut self, entity: Entity) -> Entry<'_, Entity, Entity> {
self.map.entry(entity)
}
/// Returns the corresponding mapped entity.
pub fn get(&self, entity: Entity) -> Result<Entity, MapEntitiesError> {
self.map
.get(&entity)
.cloned()
.ok_or(MapEntitiesError::EntityNotFound(entity))
}
/// An iterator visiting all keys in arbitrary order.
pub fn keys(&self) -> impl Iterator<Item = Entity> + '_ {
self.map.keys().cloned()
}
/// An iterator visiting all values in arbitrary order.
pub fn values(&self) -> impl Iterator<Item = Entity> + '_ {
self.map.values().cloned()
}
/// Returns the number of elements in the map.
pub fn len(&self) -> usize {
self.map.len()
}
/// Returns true if the map contains no elements.
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
/// An iterator visiting all (key, value) pairs in arbitrary order.
pub fn iter(&self) -> impl Iterator<Item = (Entity, Entity)> + '_ {
self.map.iter().map(|(from, to)| (*from, *to))
}
}