diff --git a/crates/bevy_ecs/src/reflect/map_entities.rs b/crates/bevy_ecs/src/reflect/map_entities.rs index dc380f9c2fd02..12db73508b648 100644 --- a/crates/bevy_ecs/src/reflect/map_entities.rs +++ b/crates/bevy_ecs/src/reflect/map_entities.rs @@ -15,6 +15,8 @@ use bevy_reflect::{FromReflect, FromType, Reflect}; #[derive(Clone)] pub struct ReflectMapEntities { map_entities: fn(&mut dyn Reflect, &mut dyn DynEntityMapper), + map_all_world_entities: fn(&mut World, &mut SceneEntityMapper), + map_world_entities: fn(&mut World, &mut SceneEntityMapper, &[Entity]), } impl ReflectMapEntities { @@ -25,6 +27,42 @@ impl ReflectMapEntities { pub fn map_entities(&self, component: &mut dyn Reflect, mapper: &mut dyn DynEntityMapper) { (self.map_entities)(component, mapper); } + + /// A general method for applying [`MapEntities`] behavior to all elements in an [`EntityHashMap`]. + /// + /// Be mindful in its usage: Works best in situations where the entities in the [`EntityHashMap`] are newly + /// created, before systems have a chance to add new components. If some of the entities referred to + /// by the [`EntityHashMap`] might already contain valid entity references, you should use [`map_world_entities`](Self::map_world_entities). + /// + /// An example of this: A scene can be loaded with `Parent` components, but then a `Parent` component can be added + /// to these entities after they have been loaded. If you reload the scene using [`map_all_world_entities`](Self::map_all_world_entities), those `Parent` + /// components with already valid entity references could be updated to point at something else entirely. + #[deprecated = "map_all_world_entities doesn't play well with Observers. Use map_entities instead."] + pub fn map_all_world_entities( + &self, + world: &mut World, + entity_map: &mut EntityHashMap, + ) { + SceneEntityMapper::world_scope(entity_map, world, self.map_all_world_entities); + } + + /// A general method for applying [`MapEntities`] behavior to elements in an [`EntityHashMap`]. Unlike + /// [`map_all_world_entities`](Self::map_all_world_entities), this is applied to specific entities, not all values + /// in the [`EntityHashMap`]. + /// + /// This is useful mostly for when you need to be careful not to update components that already contain valid entity + /// values. See [`map_all_world_entities`](Self::map_all_world_entities) for more details. + #[deprecated = "map_world_entities doesn't play well with Observers. Use map_entities instead."] + pub fn map_world_entities( + &self, + world: &mut World, + entity_map: &mut EntityHashMap, + entities: &[Entity], + ) { + SceneEntityMapper::world_scope(entity_map, world, |world, mapper| { + (self.map_world_entities)(world, mapper, entities); + }); + } } impl FromType for ReflectMapEntities { @@ -35,6 +73,25 @@ impl FromType for Reflect concrete.map_entities(&mut UnDynEntityMapper(entity_mapper)); component.apply(&concrete as _); }, + map_world_entities: |world, entity_mapper, entities| { + for &entity in entities { + if let Some(mut component) = world.get_mut::(entity) { + component.map_entities(entity_mapper); + } + } + }, + map_all_world_entities: |world, entity_mapper| { + let entities = entity_mapper + .get_map() + .values() + .copied() + .collect::>(); + for entity in &entities { + if let Some(mut component) = world.get_mut::(*entity) { + component.map_entities(entity_mapper); + } + } + }, } } }