From 5bd3bd023a2b75d912ffe67ed4901b41d030a12f Mon Sep 17 00:00:00 2001 From: Noah Date: Wed, 12 Jul 2023 01:53:33 -0400 Subject: [PATCH 01/12] Implement entity commands reflect extension --- .../bevy_ecs/src/reflect/entity_commands.rs | 318 ++++++++++++++++++ 1 file changed, 318 insertions(+) create mode 100644 crates/bevy_ecs/src/reflect/entity_commands.rs diff --git a/crates/bevy_ecs/src/reflect/entity_commands.rs b/crates/bevy_ecs/src/reflect/entity_commands.rs new file mode 100644 index 0000000000000..e6cdd6a051df2 --- /dev/null +++ b/crates/bevy_ecs/src/reflect/entity_commands.rs @@ -0,0 +1,318 @@ +use crate::system::{Command, EntityCommands}; +use crate::{entity::Entity, reflect::ReflectComponent, world::World}; +use bevy_reflect::{Reflect, TypeRegistry}; + +/// An extension trait for [`EntityCommands`] for reflection related functions +pub trait EntityCommandsReflectExtension { + /// Inserts the given boxed reflect component to the entity using the reflection data in the supplied + /// [`TypeRegistry`]. This will overwrite any previous component of the same type. + /// Panics if the entity doesn't exist or if the [`TypeRegistry`] doesn't have the reflection data + /// for the given [`Component`]. + /// + /// # Note + /// Prefer to use the typed [`EntityCommands::insert`] unless you have good reason to use reflection. + /// + /// # Example + /// + /// ```rust + /// + /// # use bevy_ecs::prelude::*; + /// # use bevy_ecs::reflect::EntityCommandsReflectExtension; + /// # use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry}; + /// + /// # #[derive(Resource)] + /// # struct TypeRegistryResource{ + /// # type_registry: TypeRegistry, + /// # } + /// // A resource that can hold any component that implements reflect as a boxed reflect component + /// #[derive(Resource)] + /// struct SpecialComponentHolder{ + /// component: Box, + /// } + /// #[derive(Component, Reflect, FromReflect, Default)] + /// #[reflect(Component)] + /// struct ComponentA(u32); + /// #[derive(Component, Reflect, FromReflect, Default)] + /// #[reflect(Component)] + /// struct ComponentB(String); + /// + /// fn insert_reflected_component( + /// mut commands: Commands, + /// mut type_registry: ResMut, + /// mut special_component_holder: ResMut + /// ) { + /// # + /// # type_registry.type_registry.register::(); + /// # let mut registration = type_registry + /// # .type_registry + /// # .get_mut(std::any::TypeId::of::()) + /// # .unwrap(); + /// # registration.insert(>::from_type()); + /// # + /// # type_registry.type_registry.register::(); + /// # let mut registration = type_registry + /// # .type_registry + /// # .get_mut(std::any::TypeId::of::()) + /// # .unwrap(); + /// # registration.insert(>::from_type()); + /// // Create a set of new boxed reflect components to use + /// let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box; + /// let boxed_reflect_component_b = Box::new(ComponentB("NineSixteen".to_string())) as Box; + /// + /// // You can overwrite the component in the resource with either ComponentA or ComponentB + /// special_component_holder.component = boxed_reflect_component_a; + /// special_component_holder.component = boxed_reflect_component_b; + /// + /// // No matter which component is in the resource and without knowing the exact type, you can + /// // use the insert_reflected entity command to insert that component into an entity. + /// commands + /// .spawn_empty() + /// .insert_reflected(special_component_holder.component.clone_value(), type_registry.type_registry.clone()); + /// } + /// + /// ``` + fn insert_reflected( + &mut self, + component: Box, + type_registry: TypeRegistry, + ) -> &mut Self; + + /// Removes the component of the same type as the supplied boxed reflect component from the entity + /// using the reflection data in the supplied [`TypeRegistry`]. Does nothing if the entity does not + /// have a component of the same type, if the [`TypeRegistry`] does not contain the reflection data + /// for the given component, or if the entity does not exist. + /// + /// # Note + /// Prefer to use the typed [`EntityCommands::remove`] unless you have good reason to use reflection. + /// + /// # Example + /// + /// ```rust + /// + /// # use bevy_ecs::prelude::*; + /// # use bevy_ecs::reflect::EntityCommandsReflectExtension; + /// # use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry}; + /// + /// # #[derive(Resource)] + /// # struct TypeRegistryResource{ + /// # type_registry: TypeRegistry, + /// # } + /// // A resource that can hold any component that implements reflect as a boxed reflect component + /// #[derive(Resource)] + /// struct SpecialComponentHolder{ + /// entity: Entity, + /// component: Box, + /// } + /// #[derive(Component, Reflect, FromReflect, Default)] + /// #[reflect(Component)] + /// struct ComponentA(u32); + /// #[derive(Component, Reflect, FromReflect, Default)] + /// #[reflect(Component)] + /// struct ComponentB(String); + /// + /// fn remove_reflected_component( + /// mut commands: Commands, + /// mut type_registry: ResMut, + /// special_component_holder: Res + /// ) { + /// # + /// # type_registry.type_registry.register::(); + /// # let mut registration = type_registry + /// # .type_registry + /// # .get_mut(std::any::TypeId::of::()) + /// # .unwrap(); + /// # registration.insert(>::from_type()); + /// # + /// # type_registry.type_registry.register::(); + /// # let mut registration = type_registry + /// # .type_registry + /// # .get_mut(std::any::TypeId::of::()) + /// # .unwrap(); + /// # registration.insert(>::from_type()); + /// // SpecialComponentHolder can hold any boxed reflect component. In this case either + /// // ComponentA or ComponentB. No matter which component is in the resource though, + /// // we can attempt to remove any component of that same type from an entity. + /// commands.entity(special_component_holder.entity) + /// .remove_reflected(special_component_holder.component.clone_value(), type_registry.type_registry.clone()); + /// } + /// + /// ``` + fn remove_reflected( + &mut self, + component: Box, + type_registry: TypeRegistry, + ) -> &mut Self; +} + +impl<'w, 's, 'a> EntityCommandsReflectExtension for EntityCommands<'w, 's, 'a> { + fn insert_reflected( + &mut self, + component: Box, + type_registry: TypeRegistry, + ) -> &mut Self { + self.commands.add(InsertReflected { + entity: self.entity, + type_registry, + component, + }); + self + } + + fn remove_reflected( + &mut self, + component: Box, + type_registry: TypeRegistry, + ) -> &mut Self { + self.commands.add(RemoveReflected { + entity: self.entity, + type_registry, + component, + }); + self + } +} + +/// A [`Command`] that adds the boxed reflect component to an entity using the data in the provided +/// [`TypeRegistry`]. +pub struct InsertReflected { + /// The entity on which the component will be inserted. + pub entity: Entity, + /// The [`TypeRegistry`] that the component is registered in and that will be used to get reflection + /// data in order to insert the component. + pub type_registry: TypeRegistry, + /// The reflect [`Component`] that will be added to the entity. + pub component: Box, +} + +impl Command for InsertReflected { + fn apply(self, world: &mut World) { + if let Some(mut entity) = world.get_entity_mut(self.entity) { + let type_info = self.component.type_name(); + if let Some(type_registration) = self.type_registry.get_with_name(type_info) { + if let Some(reflect_component) = type_registration.data::() { + reflect_component.insert(&mut entity, &*self.component); + } else { + panic!("Could not get ReflectComponent data (for component type {}) because it doesn't exist in this TypeRegistration.", self.component.type_name()); + } + } else { + panic!("Could not get type registration for component (for component {}) because it doesn't exist in the TypeRegistry.", self.component.type_name()); + } + } else { + panic!("error[B0003]: Could not insert a reflected component (of type {}) for entity {:?} because it doesn't exist in this World.", self.component.type_name(), self.entity); + } + } +} + +/// A [`Command`] that removes the component of the same type as the given boxed reflect component from +/// the provided entity. Does nothing if the entity does not have a component of the same +/// type, if the [`TypeRegistry`] does not contain the data for the given component, or if the entity +/// does not exist. +pub struct RemoveReflected { + /// The entity from which the component will be removed. + pub entity: Entity, + /// The [`TypeRegistry`] that the component is registered in and that will be used to get reflection + /// data in order to remove the component. + pub type_registry: TypeRegistry, + /// The boxed reflect [`Component`] that will be used to remove a component of the same type + /// from the entity. + pub component: Box, +} + +impl Command for RemoveReflected { + fn apply(self, world: &mut World) { + if let Some(mut entity) = world.get_entity_mut(self.entity) { + let type_info = self.component.type_name(); + if let Some(type_registration) = self.type_registry.get_with_name(type_info) { + if let Some(reflect_component) = type_registration.data::() { + reflect_component.remove(&mut entity); + } + } + } + } +} + +#[cfg(test)] +mod tests { + use crate::prelude::ReflectComponent; + use crate::reflect::EntityCommandsReflectExtension; + use crate::system::{Commands, Res, SystemState}; + use crate::{self as bevy_ecs, component::Component, world::World}; + use bevy_ecs_macros::Resource; + use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry}; + + #[derive(Resource)] + struct TypeRegistryResource { + type_registry: TypeRegistry, + } + + #[derive(Component, Reflect, FromReflect, Default)] + #[reflect(Component)] + struct ComponentA(u32); + + #[test] + fn insert_reflected() { + let mut world = World::new(); + + let mut type_registry = TypeRegistryResource { + type_registry: TypeRegistry::new(), + }; + + type_registry.type_registry.register::(); + let registration = type_registry + .type_registry + .get_mut(std::any::TypeId::of::()) + .unwrap(); + registration.insert(>::from_type()); + world.insert_resource(type_registry); + + let mut system_state: SystemState<(Commands, Res)> = + SystemState::new(&mut world); + let (mut commands, type_registry) = system_state.get_mut(&mut world); + + let entity = commands.spawn_empty().id(); + + let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box; + + commands.entity(entity).insert_reflected( + boxed_reflect_component_a, + type_registry.type_registry.clone(), + ); + system_state.apply(&mut world); + + assert!(world.entity(entity).get::().is_some()); + assert_eq!(world.entity(entity).get::().unwrap().0, 916); + } + + #[test] + fn remove_reflected() { + let mut world = World::new(); + + let mut type_registry = TypeRegistryResource { + type_registry: TypeRegistry::new(), + }; + + type_registry.type_registry.register::(); + let registration = type_registry + .type_registry + .get_mut(std::any::TypeId::of::()) + .unwrap(); + registration.insert(>::from_type()); + world.insert_resource(type_registry); + + let mut system_state: SystemState<(Commands, Res)> = + SystemState::new(&mut world); + let (mut commands, type_registry) = system_state.get_mut(&mut world); + + let entity = commands.spawn(ComponentA(0)).id(); + + let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box; + + commands.entity(entity).remove_reflected( + boxed_reflect_component_a, + type_registry.type_registry.clone(), + ); + system_state.apply(&mut world); + + assert!(world.entity(entity).get::().is_none()); + } +} From a677efc2d1bd9b325aa3a5f683b710aad016770b Mon Sep 17 00:00:00 2001 From: Noah Date: Wed, 12 Jul 2023 01:55:09 -0400 Subject: [PATCH 02/12] Implement final changes and insert_reflected_with_registry and remove_reflected_with_registry --- .../bevy_ecs/src/reflect/entity_commands.rs | 471 +++++++++++++----- 1 file changed, 357 insertions(+), 114 deletions(-) diff --git a/crates/bevy_ecs/src/reflect/entity_commands.rs b/crates/bevy_ecs/src/reflect/entity_commands.rs index e6cdd6a051df2..34aaf12f38887 100644 --- a/crates/bevy_ecs/src/reflect/entity_commands.rs +++ b/crates/bevy_ecs/src/reflect/entity_commands.rs @@ -1,16 +1,27 @@ -use crate::system::{Command, EntityCommands}; +use crate::reflect::AppTypeRegistry; +use crate::system::{Command, EntityCommands, Resource}; use crate::{entity::Entity, reflect::ReflectComponent, world::World}; use bevy_reflect::{Reflect, TypeRegistry}; +use std::marker::PhantomData; /// An extension trait for [`EntityCommands`] for reflection related functions pub trait EntityCommandsReflectExtension { - /// Inserts the given boxed reflect component to the entity using the reflection data in the supplied - /// [`TypeRegistry`]. This will overwrite any previous component of the same type. - /// Panics if the entity doesn't exist or if the [`TypeRegistry`] doesn't have the reflection data - /// for the given [`Component`]. + /// Inserts the given boxed reflect component to the entity using the reflection data in + /// [`AppTypeRegistry`]. + /// + /// This will overwrite any previous component of the same type. + /// + /// # Panics + /// + /// - If the entity doesn't exist. + /// - If [`AppTypeRegistry`] does not have the reflection data for the given [`Component`]. + /// - If the component data is invalid. See [`Reflect::apply`] for further details. + /// - If [`AppTypeRegistry`] is not present in the [`World`]. /// /// # Note - /// Prefer to use the typed [`EntityCommands::insert`] unless you have good reason to use reflection. + /// + /// Prefer to use the typed [`EntityCommands::insert`] if possible as it is optimized for insertions + /// compared to reflection which requires more overhead. /// /// # Example /// @@ -19,71 +30,172 @@ pub trait EntityCommandsReflectExtension { /// # use bevy_ecs::prelude::*; /// # use bevy_ecs::reflect::EntityCommandsReflectExtension; /// # use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry}; - /// - /// # #[derive(Resource)] - /// # struct TypeRegistryResource{ - /// # type_registry: TypeRegistry, - /// # } /// // A resource that can hold any component that implements reflect as a boxed reflect component /// #[derive(Resource)] - /// struct SpecialComponentHolder{ + /// struct Prefab{ /// component: Box, /// } - /// #[derive(Component, Reflect, FromReflect, Default)] + /// #[derive(Component, Reflect, Default)] /// #[reflect(Component)] /// struct ComponentA(u32); - /// #[derive(Component, Reflect, FromReflect, Default)] + /// + /// #[derive(Component, Reflect, Default)] /// #[reflect(Component)] /// struct ComponentB(String); /// /// fn insert_reflected_component( /// mut commands: Commands, - /// mut type_registry: ResMut, - /// mut special_component_holder: ResMut + /// mut prefab: ResMut /// ) { - /// # - /// # type_registry.type_registry.register::(); - /// # let mut registration = type_registry - /// # .type_registry - /// # .get_mut(std::any::TypeId::of::()) - /// # .unwrap(); - /// # registration.insert(>::from_type()); - /// # - /// # type_registry.type_registry.register::(); - /// # let mut registration = type_registry - /// # .type_registry - /// # .get_mut(std::any::TypeId::of::()) - /// # .unwrap(); - /// # registration.insert(>::from_type()); /// // Create a set of new boxed reflect components to use /// let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box; /// let boxed_reflect_component_b = Box::new(ComponentB("NineSixteen".to_string())) as Box; /// /// // You can overwrite the component in the resource with either ComponentA or ComponentB - /// special_component_holder.component = boxed_reflect_component_a; - /// special_component_holder.component = boxed_reflect_component_b; + /// prefab.component = boxed_reflect_component_a; + /// prefab.component = boxed_reflect_component_b; /// /// // No matter which component is in the resource and without knowing the exact type, you can /// // use the insert_reflected entity command to insert that component into an entity. /// commands /// .spawn_empty() - /// .insert_reflected(special_component_holder.component.clone_value(), type_registry.type_registry.clone()); + /// .insert_reflected(prefab.component.clone_value()); + /// } + /// + /// ``` + fn insert_reflected(&mut self, component: Box) -> &mut Self; + + /// Inserts the given boxed reflect component to the entity using the reflection data in the + /// provided [`TypeRegistry`] [Resource](Resource).. + /// + /// This will overwrite any previous component of the same type. + /// + /// # Panics + /// + /// - If the entity doesn't exist. + /// - If the given [`TypeRegistry`] does not have the reflection data for the given [`Component`]. + /// - If the component data is invalid. See [`Reflect::apply`] for further details. + /// - If the given [`Resource`] is not present in the [`World`]. + /// + /// # Note + /// + /// - Prefer to use the typed [`EntityCommands::insert`] if possible as it is optimized for insertions + /// compared to reflection which requires more overhead. + /// - The given [`Resource`] is removed from the [`World`] before the command is applied. + /// + /// # Example + /// + /// ```rust + /// + /// # use bevy_ecs::prelude::*; + /// # use bevy_ecs::reflect::EntityCommandsReflectExtension; + /// # use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry}; + /// + /// // A custom TypeRegistry Resource + /// #[derive(Resource)] + /// struct TypeRegistryResource { + /// type_registry: TypeRegistry, + /// } + /// + /// impl AsRef for TypeRegistryResource { + /// fn as_ref(&self) -> &TypeRegistry { + /// &self.type_registry + /// } + /// } + /// // A resource that can hold any component that implements reflect as a boxed reflect component + /// #[derive(Resource)] + /// struct Prefab{ + /// component: Box, + /// } + /// #[derive(Component, Reflect, Default)] + /// #[reflect(Component)] + /// struct ComponentA(u32); + /// #[derive(Component, Reflect, Default)] + /// #[reflect(Component)] + /// struct ComponentB(String); + /// + /// fn insert_reflected_component( + /// mut commands: Commands, + /// mut prefab: ResMut + /// ) { + /// // Create a set of new boxed reflect components to use + /// let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box; + /// let boxed_reflect_component_b = Box::new(ComponentB("NineSixteen".to_string())) as Box; + /// + /// // You can overwrite the component in the resource with either ComponentA or ComponentB + /// prefab.component = boxed_reflect_component_a; + /// prefab.component = boxed_reflect_component_b; + /// + /// // No matter which component is in the resource and without knowing the exact type, you can + /// // use the insert_reflected entity command to insert that component into an entity using + /// // the data in the provided resource. + /// commands + /// .spawn_empty() + /// .insert_reflected_with_registry::(prefab.component.clone_value()); /// } /// /// ``` - fn insert_reflected( + fn insert_reflected_with_registry>( &mut self, component: Box, - type_registry: TypeRegistry, ) -> &mut Self; - /// Removes the component of the same type as the supplied boxed reflect component from the entity - /// using the reflection data in the supplied [`TypeRegistry`]. Does nothing if the entity does not - /// have a component of the same type, if the [`TypeRegistry`] does not contain the reflection data - /// for the given component, or if the entity does not exist. + /// Removes the component of the same type as the component type name from the entity using the + /// reflection data from [`AppTypeRegistry`]. + /// + /// Does nothing if the entity does not have a component of the same type, if [`AppTypeRegistry`] + /// does not contain the reflection data for the given component, or if the entity does not exist. + /// + /// # Note + /// + /// Prefer to use the typed [`EntityCommands::remove`] if possible as it is optimized for removals + /// compared to reflection which requires more overhead. + /// + /// # Example + /// + /// ```rust + /// + /// # use bevy_ecs::prelude::*; + /// # use bevy_ecs::reflect::EntityCommandsReflectExtension; + /// # use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry}; + /// + /// // A resource that can hold any component that implements reflect as a boxed reflect component + /// #[derive(Resource)] + /// struct Prefab{ + /// entity: Entity, + /// component: Box, + /// } + /// #[derive(Component, Reflect, Default)] + /// #[reflect(Component)] + /// struct ComponentA(u32); + /// #[derive(Component, Reflect, Default)] + /// #[reflect(Component)] + /// struct ComponentB(String); + /// + /// fn remove_reflected_component( + /// mut commands: Commands, + /// prefab: Res + /// ) { + /// // Prefab can hold any boxed reflect component. In this case either + /// // ComponentA or ComponentB. No matter which component is in the resource though, + /// // we can attempt to remove any component of that same type from an entity. + /// commands.entity(prefab.entity) + /// .remove_reflected(prefab.component.type_name().into()); + /// } + /// + /// ``` + fn remove_reflected(&mut self, component_type_name: String) -> &mut Self; + + /// Removes the component of the same type as the given component type name from the entity + /// using the reflection data in the provided [`TypeRegistry`] [Resource](Resource). + /// + /// Does nothing if the entity does not have a component of the same type, if [`AppTypeRegistry`] + /// does not contain the reflection data for the given component, or if the entity does not exist. /// /// # Note - /// Prefer to use the typed [`EntityCommands::remove`] unless you have good reason to use reflection. + /// + /// Prefer to use the typed [`EntityCommands::remove`] if possible as it is optimized for removals + /// compared to reflection which requires more overhead. /// /// # Example /// @@ -92,110 +204,148 @@ pub trait EntityCommandsReflectExtension { /// # use bevy_ecs::prelude::*; /// # use bevy_ecs::reflect::EntityCommandsReflectExtension; /// # use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry}; + /// // A custom TypeRegistry Resource + /// #[derive(Resource)] + /// struct TypeRegistryResource { + /// type_registry: TypeRegistry, + /// } /// - /// # #[derive(Resource)] - /// # struct TypeRegistryResource{ - /// # type_registry: TypeRegistry, - /// # } + /// impl AsRef for TypeRegistryResource { + /// fn as_ref(&self) -> &TypeRegistry { + /// &self.type_registry + /// } + /// } /// // A resource that can hold any component that implements reflect as a boxed reflect component /// #[derive(Resource)] - /// struct SpecialComponentHolder{ + /// struct Prefab{ /// entity: Entity, /// component: Box, /// } - /// #[derive(Component, Reflect, FromReflect, Default)] + /// #[derive(Component, Reflect, Default)] /// #[reflect(Component)] /// struct ComponentA(u32); - /// #[derive(Component, Reflect, FromReflect, Default)] + /// #[derive(Component, Reflect, Default)] /// #[reflect(Component)] /// struct ComponentB(String); /// /// fn remove_reflected_component( /// mut commands: Commands, - /// mut type_registry: ResMut, - /// special_component_holder: Res + /// prefab: Res /// ) { - /// # - /// # type_registry.type_registry.register::(); - /// # let mut registration = type_registry - /// # .type_registry - /// # .get_mut(std::any::TypeId::of::()) - /// # .unwrap(); - /// # registration.insert(>::from_type()); - /// # - /// # type_registry.type_registry.register::(); - /// # let mut registration = type_registry - /// # .type_registry - /// # .get_mut(std::any::TypeId::of::()) - /// # .unwrap(); - /// # registration.insert(>::from_type()); - /// // SpecialComponentHolder can hold any boxed reflect component. In this case either + /// // Prefab can hold any boxed reflect component. In this case either /// // ComponentA or ComponentB. No matter which component is in the resource though, /// // we can attempt to remove any component of that same type from an entity. - /// commands.entity(special_component_holder.entity) - /// .remove_reflected(special_component_holder.component.clone_value(), type_registry.type_registry.clone()); + /// commands.entity(prefab.entity) + /// .remove_reflected_with_registry::(prefab.component.type_name().into()); /// } /// /// ``` - fn remove_reflected( + fn remove_reflected_with_registry>( &mut self, - component: Box, - type_registry: TypeRegistry, + component_type_name: String, ) -> &mut Self; } impl<'w, 's, 'a> EntityCommandsReflectExtension for EntityCommands<'w, 's, 'a> { - fn insert_reflected( - &mut self, - component: Box, - type_registry: TypeRegistry, - ) -> &mut Self { + fn insert_reflected(&mut self, component: Box) -> &mut Self { self.commands.add(InsertReflected { entity: self.entity, - type_registry, component, }); self } - fn remove_reflected( + fn insert_reflected_with_registry>( &mut self, component: Box, - type_registry: TypeRegistry, ) -> &mut Self { - self.commands.add(RemoveReflected { + self.commands.add(InsertReflectedWithRegistry:: { entity: self.entity, - type_registry, + _t: PhantomData, component, }); self } + + fn remove_reflected(&mut self, component_type_name: String) -> &mut Self { + self.commands.add(RemoveReflected { + entity: self.entity, + component_type_name, + }); + self + } + + fn remove_reflected_with_registry>( + &mut self, + component_type_name: String, + ) -> &mut Self { + self.commands.add(RemoveReflectedWithRegistry:: { + entity: self.entity, + _t: PhantomData, + component_type_name, + }); + self + } } -/// A [`Command`] that adds the boxed reflect component to an entity using the data in the provided -/// [`TypeRegistry`]. +/// A [`Command`] that adds the boxed reflect component to an entity using the data in +/// [`AppTypeRegistry`]. +/// +/// See [`EntityCommandsReflectExtension::insert_reflected`] for details. pub struct InsertReflected { /// The entity on which the component will be inserted. pub entity: Entity, - /// The [`TypeRegistry`] that the component is registered in and that will be used to get reflection - /// data in order to insert the component. - pub type_registry: TypeRegistry, /// The reflect [`Component`] that will be added to the entity. pub component: Box, } impl Command for InsertReflected { fn apply(self, world: &mut World) { + let registry = world.get_resource::().unwrap().clone(); + if let Some(mut entity) = world.get_entity_mut(self.entity) { + let type_info = self.component.type_name(); + if let Some(type_registration) = registry.read().get_with_name(type_info) { + if let Some(reflect_component) = type_registration.data::() { + reflect_component.insert(&mut entity, &*self.component); + } else { + panic!("Could not get ReflectComponent data (for component type {}) because it doesn't exist in this TypeRegistration.", self.component.type_name()); + } + } else { + panic!("Could not get type registration (for component type {}) because it doesn't exist in the TypeRegistry.", self.component.type_name()); + } + } else { + panic!("error[B0003]: Could not insert a reflected component (of type {}) for entity {:?} because it doesn't exist in this World.", self.component.type_name(), self.entity); + } + } +} + +/// A [`Command`] that adds the boxed reflect component to an entity using the data in the provided +/// [`Resource`] that implements [`AsRef`]. +/// +/// See [`EntityCommandsReflectExtension::insert_reflected_with_registry`] for details. +pub struct InsertReflectedWithRegistry> { + /// The entity on which the component will be inserted. + pub entity: Entity, + pub _t: PhantomData, + /// The reflect [`Component`] that will be added to the entity. + pub component: Box, +} + +impl> Command for InsertReflectedWithRegistry { + fn apply(self, world: &mut World) { + let registry = world.remove_resource::().unwrap(); + let registry: &TypeRegistry = registry.as_ref(); + if let Some(mut entity) = world.get_entity_mut(self.entity) { let type_info = self.component.type_name(); - if let Some(type_registration) = self.type_registry.get_with_name(type_info) { + if let Some(type_registration) = registry.get_with_name(type_info) { if let Some(reflect_component) = type_registration.data::() { reflect_component.insert(&mut entity, &*self.component); } else { panic!("Could not get ReflectComponent data (for component type {}) because it doesn't exist in this TypeRegistration.", self.component.type_name()); } } else { - panic!("Could not get type registration for component (for component {}) because it doesn't exist in the TypeRegistry.", self.component.type_name()); + panic!("Could not get type registration (for component type {}) because it doesn't exist in the TypeRegistry.", self.component.type_name()); } } else { panic!("error[B0003]: Could not insert a reflected component (of type {}) for entity {:?} because it doesn't exist in this World.", self.component.type_name(), self.entity); @@ -203,26 +353,56 @@ impl Command for InsertReflected { } } -/// A [`Command`] that removes the component of the same type as the given boxed reflect component from -/// the provided entity. Does nothing if the entity does not have a component of the same -/// type, if the [`TypeRegistry`] does not contain the data for the given component, or if the entity -/// does not exist. +/// A [`Command`] that removes the component of the same type as the given component type name from +/// the provided entity. +/// +/// See [`EntityCommandsReflectExtension::remove_reflected`] for details. pub struct RemoveReflected { /// The entity from which the component will be removed. pub entity: Entity, - /// The [`TypeRegistry`] that the component is registered in and that will be used to get reflection - /// data in order to remove the component. - pub type_registry: TypeRegistry, /// The boxed reflect [`Component`] that will be used to remove a component of the same type /// from the entity. - pub component: Box, + pub component_type_name: String, } impl Command for RemoveReflected { fn apply(self, world: &mut World) { + let registry = world.get_resource::().unwrap().clone(); if let Some(mut entity) = world.get_entity_mut(self.entity) { - let type_info = self.component.type_name(); - if let Some(type_registration) = self.type_registry.get_with_name(type_info) { + if let Some(type_registration) = registry + .read() + .get_with_name(self.component_type_name.as_ref()) + { + if let Some(reflect_component) = type_registration.data::() { + reflect_component.remove(&mut entity); + } + } + } + } +} + +/// A [`Command`] that removes the component of the same type as the given component type name from +/// the provided entity using the provided [`Resource`] that implements [`AsRef`]. +/// +/// See [`EntityCommandsReflectExtension::remove_reflected_with_registry`] for details. +pub struct RemoveReflectedWithRegistry> { + /// The entity from which the component will be removed. + pub entity: Entity, + pub _t: PhantomData, + /// The boxed reflect [`Component`] that will be used to remove a component of the same type + /// from the entity. + pub component_type_name: String, +} + +impl> Command for RemoveReflectedWithRegistry { + fn apply(self, world: &mut World) { + let registry = world.remove_resource::().unwrap(); + let registry: &TypeRegistry = registry.as_ref(); + + if let Some(mut entity) = world.get_entity_mut(self.entity) { + if let Some(type_registration) = + registry.get_with_name(self.component_type_name.as_ref()) + { if let Some(reflect_component) = type_registration.data::() { reflect_component.remove(&mut entity); } @@ -233,19 +413,25 @@ impl Command for RemoveReflected { #[cfg(test)] mod tests { - use crate::prelude::ReflectComponent; + use crate::prelude::{AppTypeRegistry, ReflectComponent}; use crate::reflect::EntityCommandsReflectExtension; - use crate::system::{Commands, Res, SystemState}; + use crate::system::{Commands, SystemState}; use crate::{self as bevy_ecs, component::Component, world::World}; use bevy_ecs_macros::Resource; - use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry}; + use bevy_reflect::{FromType, Reflect, TypeRegistry}; #[derive(Resource)] struct TypeRegistryResource { type_registry: TypeRegistry, } - #[derive(Component, Reflect, FromReflect, Default)] + impl AsRef for TypeRegistryResource { + fn as_ref(&self) -> &TypeRegistry { + &self.type_registry + } + } + + #[derive(Component, Reflect, Default)] #[reflect(Component)] struct ComponentA(u32); @@ -253,6 +439,36 @@ mod tests { fn insert_reflected() { let mut world = World::new(); + let type_registry = AppTypeRegistry::default(); + let mut registry = type_registry.write(); + registry.register::(); + let registration = registry + .get_mut(std::any::TypeId::of::()) + .unwrap(); + registration.insert(>::from_type()); + drop(registry); + world.insert_resource(type_registry); + + let mut system_state: SystemState = SystemState::new(&mut world); + let mut commands = system_state.get_mut(&mut world); + + let entity = commands.spawn_empty().id(); + + let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box; + + commands + .entity(entity) + .insert_reflected(boxed_reflect_component_a); + system_state.apply(&mut world); + + assert!(world.entity(entity).get::().is_some()); + assert_eq!(world.entity(entity).get::().unwrap().0, 916); + } + + #[test] + fn insert_reflected_with_registry() { + let mut world = World::new(); + let mut type_registry = TypeRegistryResource { type_registry: TypeRegistry::new(), }; @@ -265,18 +481,16 @@ mod tests { registration.insert(>::from_type()); world.insert_resource(type_registry); - let mut system_state: SystemState<(Commands, Res)> = - SystemState::new(&mut world); - let (mut commands, type_registry) = system_state.get_mut(&mut world); + let mut system_state: SystemState = SystemState::new(&mut world); + let mut commands = system_state.get_mut(&mut world); let entity = commands.spawn_empty().id(); let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box; - commands.entity(entity).insert_reflected( - boxed_reflect_component_a, - type_registry.type_registry.clone(), - ); + commands + .entity(entity) + .insert_reflected_with_registry::(boxed_reflect_component_a); system_state.apply(&mut world); assert!(world.entity(entity).get::().is_some()); @@ -287,6 +501,35 @@ mod tests { fn remove_reflected() { let mut world = World::new(); + let type_registry = AppTypeRegistry::default(); + let mut registry = type_registry.write(); + registry.register::(); + let registration = registry + .get_mut(std::any::TypeId::of::()) + .unwrap(); + registration.insert(>::from_type()); + drop(registry); + world.insert_resource(type_registry); + + let mut system_state: SystemState = SystemState::new(&mut world); + let mut commands = system_state.get_mut(&mut world); + + let entity = commands.spawn(ComponentA(0)).id(); + + let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box; + + commands + .entity(entity) + .remove_reflected(boxed_reflect_component_a.type_name().into()); + system_state.apply(&mut world); + + assert!(world.entity(entity).get::().is_none()); + } + + #[test] + fn remove_reflected_with_registry() { + let mut world = World::new(); + let mut type_registry = TypeRegistryResource { type_registry: TypeRegistry::new(), }; @@ -299,18 +542,18 @@ mod tests { registration.insert(>::from_type()); world.insert_resource(type_registry); - let mut system_state: SystemState<(Commands, Res)> = - SystemState::new(&mut world); - let (mut commands, type_registry) = system_state.get_mut(&mut world); + let mut system_state: SystemState = SystemState::new(&mut world); + let mut commands = system_state.get_mut(&mut world); let entity = commands.spawn(ComponentA(0)).id(); let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box; - commands.entity(entity).remove_reflected( - boxed_reflect_component_a, - type_registry.type_registry.clone(), - ); + commands + .entity(entity) + .remove_reflected_with_registry::( + boxed_reflect_component_a.type_name().into(), + ); system_state.apply(&mut world); assert!(world.entity(entity).get::().is_none()); From 61a59d03c04f07c4daaf4be1032f7cbcbd34590b Mon Sep 17 00:00:00 2001 From: Noah Date: Wed, 12 Jul 2023 02:02:35 -0400 Subject: [PATCH 03/12] Make EntityCommands fields pub(crate) --- crates/bevy_ecs/src/system/commands/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index fac21c7c0ffc2..59b51ad74562a 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -642,8 +642,8 @@ impl Command for WithEntity { /// A list of commands that will be run to modify an [entity](crate::entity). pub struct EntityCommands<'w, 's, 'a> { - entity: Entity, - commands: &'a mut Commands<'w, 's>, + pub(crate) entity: Entity, + pub(crate) commands: &'a mut Commands<'w, 's>, } impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> { From 760bb6c83ecfeeb26d5ab48972823050001c077d Mon Sep 17 00:00:00 2001 From: Noah Date: Wed, 12 Jul 2023 02:02:59 -0400 Subject: [PATCH 04/12] add entity_commands module and pub use statement for EntityCommandsReflectExtension --- crates/bevy_ecs/src/reflect/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/bevy_ecs/src/reflect/mod.rs b/crates/bevy_ecs/src/reflect/mod.rs index bcfb1770b770a..b23a4fae352f0 100644 --- a/crates/bevy_ecs/src/reflect/mod.rs +++ b/crates/bevy_ecs/src/reflect/mod.rs @@ -9,8 +9,10 @@ use bevy_reflect::{impl_reflect_value, ReflectDeserialize, ReflectSerialize, Typ mod component; mod map_entities; mod resource; +mod entity_commands; pub use component::{ReflectComponent, ReflectComponentFns}; +pub use entity_commands::EntityCommandsReflectExtension; pub use map_entities::ReflectMapEntities; pub use resource::{ReflectResource, ReflectResourceFns}; From e1762aa6d51c144c2283af0d8a5a50a5d5381857 Mon Sep 17 00:00:00 2001 From: Noah Date: Wed, 12 Jul 2023 02:14:56 -0400 Subject: [PATCH 05/12] cargo fmt --- crates/bevy_ecs/src/reflect/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/reflect/mod.rs b/crates/bevy_ecs/src/reflect/mod.rs index b23a4fae352f0..543e57da63fb0 100644 --- a/crates/bevy_ecs/src/reflect/mod.rs +++ b/crates/bevy_ecs/src/reflect/mod.rs @@ -7,9 +7,9 @@ use crate::{entity::Entity, system::Resource}; use bevy_reflect::{impl_reflect_value, ReflectDeserialize, ReflectSerialize, TypeRegistryArc}; mod component; +mod entity_commands; mod map_entities; mod resource; -mod entity_commands; pub use component::{ReflectComponent, ReflectComponentFns}; pub use entity_commands::EntityCommandsReflectExtension; From 666fd764fc473f1766e4dd5cb6dd5f2bddc19814 Mon Sep 17 00:00:00 2001 From: Noah Date: Wed, 12 Jul 2023 02:19:28 -0400 Subject: [PATCH 06/12] Documentation fixes --- crates/bevy_ecs/src/reflect/entity_commands.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/bevy_ecs/src/reflect/entity_commands.rs b/crates/bevy_ecs/src/reflect/entity_commands.rs index 34aaf12f38887..033e915af9b85 100644 --- a/crates/bevy_ecs/src/reflect/entity_commands.rs +++ b/crates/bevy_ecs/src/reflect/entity_commands.rs @@ -1,6 +1,6 @@ use crate::reflect::AppTypeRegistry; use crate::system::{Command, EntityCommands, Resource}; -use crate::{entity::Entity, reflect::ReflectComponent, world::World}; +use crate::{ entity::Entity, reflect::ReflectComponent, world::World}; use bevy_reflect::{Reflect, TypeRegistry}; use std::marker::PhantomData; @@ -14,7 +14,7 @@ pub trait EntityCommandsReflectExtension { /// # Panics /// /// - If the entity doesn't exist. - /// - If [`AppTypeRegistry`] does not have the reflection data for the given [`Component`]. + /// - If [`AppTypeRegistry`] does not have the reflection data for the given [Component](crate::component::Component). /// - If the component data is invalid. See [`Reflect::apply`] for further details. /// - If [`AppTypeRegistry`] is not present in the [`World`]. /// @@ -73,7 +73,7 @@ pub trait EntityCommandsReflectExtension { /// # Panics /// /// - If the entity doesn't exist. - /// - If the given [`TypeRegistry`] does not have the reflection data for the given [`Component`]. + /// - If the given [`TypeRegistry`] does not have the reflection data for the given [Component](crate::component::Component). /// - If the component data is invalid. See [`Reflect::apply`] for further details. /// - If the given [`Resource`] is not present in the [`World`]. /// @@ -295,7 +295,7 @@ impl<'w, 's, 'a> EntityCommandsReflectExtension for EntityCommands<'w, 's, 'a> { pub struct InsertReflected { /// The entity on which the component will be inserted. pub entity: Entity, - /// The reflect [`Component`] that will be added to the entity. + /// The reflect [Component](crate::component::Component) that will be added to the entity. pub component: Box, } @@ -327,7 +327,7 @@ pub struct InsertReflectedWithRegistry> { /// The entity on which the component will be inserted. pub entity: Entity, pub _t: PhantomData, - /// The reflect [`Component`] that will be added to the entity. + /// The reflect [Component](crate::component::Component) that will be added to the entity. pub component: Box, } @@ -360,8 +360,8 @@ impl> Command for InsertReflectedWithRegistry< pub struct RemoveReflected { /// The entity from which the component will be removed. pub entity: Entity, - /// The boxed reflect [`Component`] that will be used to remove a component of the same type - /// from the entity. + /// The [Component](crate::component::Component) type name that will be used to remove a component + /// of the same type from the entity. pub component_type_name: String, } @@ -389,8 +389,8 @@ pub struct RemoveReflectedWithRegistry> { /// The entity from which the component will be removed. pub entity: Entity, pub _t: PhantomData, - /// The boxed reflect [`Component`] that will be used to remove a component of the same type - /// from the entity. + /// The [Component](crate::component::Component) type name that will be used to remove a component + /// of the same type from the entity. pub component_type_name: String, } From dde9e27687edba6b6e165c824f3d3e0b6f3b81d1 Mon Sep 17 00:00:00 2001 From: Noah Date: Wed, 12 Jul 2023 11:17:06 -0400 Subject: [PATCH 07/12] cargo fmt entity_commands.rs --- crates/bevy_ecs/src/reflect/entity_commands.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_ecs/src/reflect/entity_commands.rs b/crates/bevy_ecs/src/reflect/entity_commands.rs index 033e915af9b85..437e21ceef5fa 100644 --- a/crates/bevy_ecs/src/reflect/entity_commands.rs +++ b/crates/bevy_ecs/src/reflect/entity_commands.rs @@ -1,6 +1,6 @@ use crate::reflect::AppTypeRegistry; use crate::system::{Command, EntityCommands, Resource}; -use crate::{ entity::Entity, reflect::ReflectComponent, world::World}; +use crate::{entity::Entity, reflect::ReflectComponent, world::World}; use bevy_reflect::{Reflect, TypeRegistry}; use std::marker::PhantomData; @@ -360,7 +360,7 @@ impl> Command for InsertReflectedWithRegistry< pub struct RemoveReflected { /// The entity from which the component will be removed. pub entity: Entity, - /// The [Component](crate::component::Component) type name that will be used to remove a component + /// The [Component](crate::component::Component) type name that will be used to remove a component /// of the same type from the entity. pub component_type_name: String, } @@ -389,7 +389,7 @@ pub struct RemoveReflectedWithRegistry> { /// The entity from which the component will be removed. pub entity: Entity, pub _t: PhantomData, - /// The [Component](crate::component::Component) type name that will be used to remove a component + /// The [Component](crate::component::Component) type name that will be used to remove a component /// of the same type from the entity. pub component_type_name: String, } From e3d1d6a3bc6dee4c3943750cffe7d91312ab859d Mon Sep 17 00:00:00 2001 From: Noah Date: Wed, 12 Jul 2023 11:21:16 -0400 Subject: [PATCH 08/12] remove bom to pass ci --- crates/bevy_ecs/src/reflect/entity_commands.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/reflect/entity_commands.rs b/crates/bevy_ecs/src/reflect/entity_commands.rs index 437e21ceef5fa..46e0292edfe45 100644 --- a/crates/bevy_ecs/src/reflect/entity_commands.rs +++ b/crates/bevy_ecs/src/reflect/entity_commands.rs @@ -1,4 +1,4 @@ -use crate::reflect::AppTypeRegistry; +use crate::reflect::AppTypeRegistry; use crate::system::{Command, EntityCommands, Resource}; use crate::{entity::Entity, reflect::ReflectComponent, world::World}; use bevy_reflect::{Reflect, TypeRegistry}; From 8f9131228ee31d128c8e373bddc71b22559e42d2 Mon Sep 17 00:00:00 2001 From: Noah Date: Thu, 10 Aug 2023 12:16:05 -0400 Subject: [PATCH 09/12] Impl feedback --- .../bevy_ecs/src/reflect/entity_commands.rs | 242 +++++------------- crates/bevy_ecs/src/reflect/mod.rs | 2 +- 2 files changed, 67 insertions(+), 177 deletions(-) diff --git a/crates/bevy_ecs/src/reflect/entity_commands.rs b/crates/bevy_ecs/src/reflect/entity_commands.rs index 46e0292edfe45..b231108533b12 100644 --- a/crates/bevy_ecs/src/reflect/entity_commands.rs +++ b/crates/bevy_ecs/src/reflect/entity_commands.rs @@ -2,11 +2,12 @@ use crate::reflect::AppTypeRegistry; use crate::system::{Command, EntityCommands, Resource}; use crate::{entity::Entity, reflect::ReflectComponent, world::World}; use bevy_reflect::{Reflect, TypeRegistry}; +use std::borrow::Cow; use std::marker::PhantomData; /// An extension trait for [`EntityCommands`] for reflection related functions -pub trait EntityCommandsReflectExtension { - /// Inserts the given boxed reflect component to the entity using the reflection data in +pub trait ReflectCommandExt { + /// Adds the given boxed reflect component to the entity using the reflection data in /// [`AppTypeRegistry`]. /// /// This will overwrite any previous component of the same type. @@ -14,21 +15,24 @@ pub trait EntityCommandsReflectExtension { /// # Panics /// /// - If the entity doesn't exist. - /// - If [`AppTypeRegistry`] does not have the reflection data for the given [Component](crate::component::Component). + /// - If [`AppTypeRegistry`] does not have the reflection data for the given [`Component`](crate::component::Component). /// - If the component data is invalid. See [`Reflect::apply`] for further details. /// - If [`AppTypeRegistry`] is not present in the [`World`]. /// /// # Note /// - /// Prefer to use the typed [`EntityCommands::insert`] if possible as it is optimized for insertions - /// compared to reflection which requires more overhead. + /// Prefer to use the typed [`EntityCommands::insert`] if possible. Adding a reflected component + /// is much slower. /// /// # Example /// /// ```rust + /// // Note that you need to register the component type in the AppTypeRegistry prior to using + /// // reflection. You can use the helpers on the App with `app.register_type::()` + /// // or write to the TypeRegistry directly to register all your components /// /// # use bevy_ecs::prelude::*; - /// # use bevy_ecs::reflect::EntityCommandsReflectExtension; + /// # use bevy_ecs::reflect::ReflectCommandExt; /// # use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry}; /// // A resource that can hold any component that implements reflect as a boxed reflect component /// #[derive(Resource)] @@ -43,7 +47,7 @@ pub trait EntityCommandsReflectExtension { /// #[reflect(Component)] /// struct ComponentB(String); /// - /// fn insert_reflected_component( + /// fn insert_reflect_component( /// mut commands: Commands, /// mut prefab: ResMut /// ) { @@ -56,165 +60,51 @@ pub trait EntityCommandsReflectExtension { /// prefab.component = boxed_reflect_component_b; /// /// // No matter which component is in the resource and without knowing the exact type, you can - /// // use the insert_reflected entity command to insert that component into an entity. + /// // use the insert_reflect entity command to insert that component into an entity. /// commands /// .spawn_empty() - /// .insert_reflected(prefab.component.clone_value()); + /// .insert_reflect(prefab.component.clone_value()); /// } /// /// ``` - fn insert_reflected(&mut self, component: Box) -> &mut Self; + fn insert_reflect(&mut self, component: Box) -> &mut Self; - /// Inserts the given boxed reflect component to the entity using the reflection data in the - /// provided [`TypeRegistry`] [Resource](Resource).. - /// - /// This will overwrite any previous component of the same type. + /// Same as [`insert_reflect`](ReflectCommandExt::insert_reflect), but using the `T` resource as type registry instead of + /// `AppTypeRegistry`. /// /// # Panics /// - /// - If the entity doesn't exist. - /// - If the given [`TypeRegistry`] does not have the reflection data for the given [Component](crate::component::Component). - /// - If the component data is invalid. See [`Reflect::apply`] for further details. /// - If the given [`Resource`] is not present in the [`World`]. /// /// # Note /// - /// - Prefer to use the typed [`EntityCommands::insert`] if possible as it is optimized for insertions - /// compared to reflection which requires more overhead. /// - The given [`Resource`] is removed from the [`World`] before the command is applied. - /// - /// # Example - /// - /// ```rust - /// - /// # use bevy_ecs::prelude::*; - /// # use bevy_ecs::reflect::EntityCommandsReflectExtension; - /// # use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry}; - /// - /// // A custom TypeRegistry Resource - /// #[derive(Resource)] - /// struct TypeRegistryResource { - /// type_registry: TypeRegistry, - /// } - /// - /// impl AsRef for TypeRegistryResource { - /// fn as_ref(&self) -> &TypeRegistry { - /// &self.type_registry - /// } - /// } - /// // A resource that can hold any component that implements reflect as a boxed reflect component - /// #[derive(Resource)] - /// struct Prefab{ - /// component: Box, - /// } - /// #[derive(Component, Reflect, Default)] - /// #[reflect(Component)] - /// struct ComponentA(u32); - /// #[derive(Component, Reflect, Default)] - /// #[reflect(Component)] - /// struct ComponentB(String); - /// - /// fn insert_reflected_component( - /// mut commands: Commands, - /// mut prefab: ResMut - /// ) { - /// // Create a set of new boxed reflect components to use - /// let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box; - /// let boxed_reflect_component_b = Box::new(ComponentB("NineSixteen".to_string())) as Box; - /// - /// // You can overwrite the component in the resource with either ComponentA or ComponentB - /// prefab.component = boxed_reflect_component_a; - /// prefab.component = boxed_reflect_component_b; - /// - /// // No matter which component is in the resource and without knowing the exact type, you can - /// // use the insert_reflected entity command to insert that component into an entity using - /// // the data in the provided resource. - /// commands - /// .spawn_empty() - /// .insert_reflected_with_registry::(prefab.component.clone_value()); - /// } - /// - /// ``` - fn insert_reflected_with_registry>( + fn insert_reflect_with_registry>( &mut self, component: Box, ) -> &mut Self; - /// Removes the component of the same type as the component type name from the entity using the - /// reflection data from [`AppTypeRegistry`]. - /// - /// Does nothing if the entity does not have a component of the same type, if [`AppTypeRegistry`] - /// does not contain the reflection data for the given component, or if the entity does not exist. - /// - /// # Note - /// - /// Prefer to use the typed [`EntityCommands::remove`] if possible as it is optimized for removals - /// compared to reflection which requires more overhead. - /// - /// # Example - /// - /// ```rust - /// - /// # use bevy_ecs::prelude::*; - /// # use bevy_ecs::reflect::EntityCommandsReflectExtension; - /// # use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry}; - /// - /// // A resource that can hold any component that implements reflect as a boxed reflect component - /// #[derive(Resource)] - /// struct Prefab{ - /// entity: Entity, - /// component: Box, - /// } - /// #[derive(Component, Reflect, Default)] - /// #[reflect(Component)] - /// struct ComponentA(u32); - /// #[derive(Component, Reflect, Default)] - /// #[reflect(Component)] - /// struct ComponentB(String); - /// - /// fn remove_reflected_component( - /// mut commands: Commands, - /// prefab: Res - /// ) { - /// // Prefab can hold any boxed reflect component. In this case either - /// // ComponentA or ComponentB. No matter which component is in the resource though, - /// // we can attempt to remove any component of that same type from an entity. - /// commands.entity(prefab.entity) - /// .remove_reflected(prefab.component.type_name().into()); - /// } - /// - /// ``` - fn remove_reflected(&mut self, component_type_name: String) -> &mut Self; - - /// Removes the component of the same type as the given component type name from the entity - /// using the reflection data in the provided [`TypeRegistry`] [Resource](Resource). + /// Removes from the entity the component with the given type name registered in [`AppTypeRegistry`] /// /// Does nothing if the entity does not have a component of the same type, if [`AppTypeRegistry`] /// does not contain the reflection data for the given component, or if the entity does not exist. /// /// # Note /// - /// Prefer to use the typed [`EntityCommands::remove`] if possible as it is optimized for removals - /// compared to reflection which requires more overhead. + /// Prefer to use the typed [`EntityCommands::remove`] if possible. Removing a reflected component + /// is much slower. /// /// # Example /// /// ```rust + /// // Note that you need to register the component type in the AppTypeRegistry prior to using + /// // reflection. You can use the helpers on the App with `app.register_type::()` + /// // or write to the TypeRegistry directly to register all your components /// /// # use bevy_ecs::prelude::*; - /// # use bevy_ecs::reflect::EntityCommandsReflectExtension; + /// # use bevy_ecs::reflect::ReflectCommandExt; /// # use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry}; - /// // A custom TypeRegistry Resource - /// #[derive(Resource)] - /// struct TypeRegistryResource { - /// type_registry: TypeRegistry, - /// } /// - /// impl AsRef for TypeRegistryResource { - /// fn as_ref(&self) -> &TypeRegistry { - /// &self.type_registry - /// } - /// } /// // A resource that can hold any component that implements reflect as a boxed reflect component /// #[derive(Resource)] /// struct Prefab{ @@ -228,7 +118,7 @@ pub trait EntityCommandsReflectExtension { /// #[reflect(Component)] /// struct ComponentB(String); /// - /// fn remove_reflected_component( + /// fn remove_reflect_component( /// mut commands: Commands, /// prefab: Res /// ) { @@ -236,30 +126,33 @@ pub trait EntityCommandsReflectExtension { /// // ComponentA or ComponentB. No matter which component is in the resource though, /// // we can attempt to remove any component of that same type from an entity. /// commands.entity(prefab.entity) - /// .remove_reflected_with_registry::(prefab.component.type_name().into()); + /// .remove_reflect(prefab.component.type_name().to_owned()); /// } /// /// ``` - fn remove_reflected_with_registry>( + fn remove_reflect(&mut self, component_type_name: impl Into>) -> &mut Self; + /// Same as [`remove_reflect`](ReflectCommandExt::remove_reflect), but using the `T` resource as type registry instead of + /// `AppTypeRegistry`. + fn remove_reflect_with_registry>( &mut self, - component_type_name: String, + component_type_name: impl Into>, ) -> &mut Self; } -impl<'w, 's, 'a> EntityCommandsReflectExtension for EntityCommands<'w, 's, 'a> { - fn insert_reflected(&mut self, component: Box) -> &mut Self { - self.commands.add(InsertReflected { +impl<'w, 's, 'a> ReflectCommandExt for EntityCommands<'w, 's, 'a> { + fn insert_reflect(&mut self, component: Box) -> &mut Self { + self.commands.add(InsertReflect { entity: self.entity, component, }); self } - fn insert_reflected_with_registry>( + fn insert_reflect_with_registry>( &mut self, component: Box, ) -> &mut Self { - self.commands.add(InsertReflectedWithRegistry:: { + self.commands.add(InsertReflectWithRegistry:: { entity: self.entity, _t: PhantomData, component, @@ -267,22 +160,22 @@ impl<'w, 's, 'a> EntityCommandsReflectExtension for EntityCommands<'w, 's, 'a> { self } - fn remove_reflected(&mut self, component_type_name: String) -> &mut Self { - self.commands.add(RemoveReflected { + fn remove_reflect(&mut self, component_type_name: impl Into>) -> &mut Self { + self.commands.add(RemoveReflect { entity: self.entity, - component_type_name, + component_type_name: component_type_name.into(), }); self } - fn remove_reflected_with_registry>( + fn remove_reflect_with_registry>( &mut self, - component_type_name: String, + component_type_name: impl Into>, ) -> &mut Self { - self.commands.add(RemoveReflectedWithRegistry:: { + self.commands.add(RemoveReflectWithRegistry:: { entity: self.entity, _t: PhantomData, - component_type_name, + component_type_name: component_type_name.into(), }); self } @@ -291,15 +184,15 @@ impl<'w, 's, 'a> EntityCommandsReflectExtension for EntityCommands<'w, 's, 'a> { /// A [`Command`] that adds the boxed reflect component to an entity using the data in /// [`AppTypeRegistry`]. /// -/// See [`EntityCommandsReflectExtension::insert_reflected`] for details. -pub struct InsertReflected { +/// See [`ReflectCommandExt::insert_reflect`] for details. +pub struct InsertReflect { /// The entity on which the component will be inserted. pub entity: Entity, /// The reflect [Component](crate::component::Component) that will be added to the entity. pub component: Box, } -impl Command for InsertReflected { +impl Command for InsertReflect { fn apply(self, world: &mut World) { let registry = world.get_resource::().unwrap().clone(); if let Some(mut entity) = world.get_entity_mut(self.entity) { @@ -322,8 +215,8 @@ impl Command for InsertReflected { /// A [`Command`] that adds the boxed reflect component to an entity using the data in the provided /// [`Resource`] that implements [`AsRef`]. /// -/// See [`EntityCommandsReflectExtension::insert_reflected_with_registry`] for details. -pub struct InsertReflectedWithRegistry> { +/// See [`ReflectCommandExt::insert_reflect_with_registry`] for details. +pub struct InsertReflectWithRegistry> { /// The entity on which the component will be inserted. pub entity: Entity, pub _t: PhantomData, @@ -331,7 +224,7 @@ pub struct InsertReflectedWithRegistry> { pub component: Box, } -impl> Command for InsertReflectedWithRegistry { +impl> Command for InsertReflectWithRegistry { fn apply(self, world: &mut World) { let registry = world.remove_resource::().unwrap(); let registry: &TypeRegistry = registry.as_ref(); @@ -356,22 +249,21 @@ impl> Command for InsertReflectedWithRegistry< /// A [`Command`] that removes the component of the same type as the given component type name from /// the provided entity. /// -/// See [`EntityCommandsReflectExtension::remove_reflected`] for details. -pub struct RemoveReflected { +/// See [`ReflectCommandExt::remove_reflect`] for details. +pub struct RemoveReflect { /// The entity from which the component will be removed. pub entity: Entity, /// The [Component](crate::component::Component) type name that will be used to remove a component /// of the same type from the entity. - pub component_type_name: String, + pub component_type_name: Cow<'static, str>, } -impl Command for RemoveReflected { +impl Command for RemoveReflect { fn apply(self, world: &mut World) { let registry = world.get_resource::().unwrap().clone(); if let Some(mut entity) = world.get_entity_mut(self.entity) { - if let Some(type_registration) = registry - .read() - .get_with_name(self.component_type_name.as_ref()) + if let Some(type_registration) = + registry.read().get_with_name(&self.component_type_name) { if let Some(reflect_component) = type_registration.data::() { reflect_component.remove(&mut entity); @@ -384,25 +276,23 @@ impl Command for RemoveReflected { /// A [`Command`] that removes the component of the same type as the given component type name from /// the provided entity using the provided [`Resource`] that implements [`AsRef`]. /// -/// See [`EntityCommandsReflectExtension::remove_reflected_with_registry`] for details. -pub struct RemoveReflectedWithRegistry> { +/// See [`ReflectCommandExt::remove_reflect_with_registry`] for details. +pub struct RemoveReflectWithRegistry> { /// The entity from which the component will be removed. pub entity: Entity, pub _t: PhantomData, /// The [Component](crate::component::Component) type name that will be used to remove a component /// of the same type from the entity. - pub component_type_name: String, + pub component_type_name: Cow<'static, str>, } -impl> Command for RemoveReflectedWithRegistry { +impl> Command for RemoveReflectWithRegistry { fn apply(self, world: &mut World) { let registry = world.remove_resource::().unwrap(); let registry: &TypeRegistry = registry.as_ref(); if let Some(mut entity) = world.get_entity_mut(self.entity) { - if let Some(type_registration) = - registry.get_with_name(self.component_type_name.as_ref()) - { + if let Some(type_registration) = registry.get_with_name(&self.component_type_name) { if let Some(reflect_component) = type_registration.data::() { reflect_component.remove(&mut entity); } @@ -414,7 +304,7 @@ impl> Command for RemoveReflectedWithRegistry< #[cfg(test)] mod tests { use crate::prelude::{AppTypeRegistry, ReflectComponent}; - use crate::reflect::EntityCommandsReflectExtension; + use crate::reflect::ReflectCommandExt; use crate::system::{Commands, SystemState}; use crate::{self as bevy_ecs, component::Component, world::World}; use bevy_ecs_macros::Resource; @@ -458,7 +348,7 @@ mod tests { commands .entity(entity) - .insert_reflected(boxed_reflect_component_a); + .insert_reflect(boxed_reflect_component_a); system_state.apply(&mut world); assert!(world.entity(entity).get::().is_some()); @@ -490,7 +380,7 @@ mod tests { commands .entity(entity) - .insert_reflected_with_registry::(boxed_reflect_component_a); + .insert_reflect_with_registry::(boxed_reflect_component_a); system_state.apply(&mut world); assert!(world.entity(entity).get::().is_some()); @@ -520,7 +410,7 @@ mod tests { commands .entity(entity) - .remove_reflected(boxed_reflect_component_a.type_name().into()); + .remove_reflect(boxed_reflect_component_a.type_name().to_owned()); system_state.apply(&mut world); assert!(world.entity(entity).get::().is_none()); @@ -551,8 +441,8 @@ mod tests { commands .entity(entity) - .remove_reflected_with_registry::( - boxed_reflect_component_a.type_name().into(), + .remove_reflect_with_registry::( + boxed_reflect_component_a.type_name().to_owned(), ); system_state.apply(&mut world); diff --git a/crates/bevy_ecs/src/reflect/mod.rs b/crates/bevy_ecs/src/reflect/mod.rs index 543e57da63fb0..66cfeacde0948 100644 --- a/crates/bevy_ecs/src/reflect/mod.rs +++ b/crates/bevy_ecs/src/reflect/mod.rs @@ -12,7 +12,7 @@ mod map_entities; mod resource; pub use component::{ReflectComponent, ReflectComponentFns}; -pub use entity_commands::EntityCommandsReflectExtension; +pub use entity_commands::ReflectCommandExt; pub use map_entities::ReflectMapEntities; pub use resource::{ReflectResource, ReflectResourceFns}; From 0a9cd4b8f74a67a6fd0d52b2321cc572b0634e3e Mon Sep 17 00:00:00 2001 From: Noah Date: Thu, 17 Aug 2023 12:45:15 -0400 Subject: [PATCH 10/12] impl feedback --- .../bevy_ecs/src/reflect/entity_commands.rs | 159 +++++++++--------- 1 file changed, 80 insertions(+), 79 deletions(-) diff --git a/crates/bevy_ecs/src/reflect/entity_commands.rs b/crates/bevy_ecs/src/reflect/entity_commands.rs index b231108533b12..6aa6a0830e43a 100644 --- a/crates/bevy_ecs/src/reflect/entity_commands.rs +++ b/crates/bevy_ecs/src/reflect/entity_commands.rs @@ -52,8 +52,8 @@ pub trait ReflectCommandExt { /// mut prefab: ResMut /// ) { /// // Create a set of new boxed reflect components to use - /// let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box; - /// let boxed_reflect_component_b = Box::new(ComponentB("NineSixteen".to_string())) as Box; + /// let boxed_reflect_component_a: Box = Box::new(ComponentA(916)); + /// let boxed_reflect_component_b: Box = Box::new(ComponentB("NineSixteen".to_string())); /// /// // You can overwrite the component in the resource with either ComponentA or ComponentB /// prefab.component = boxed_reflect_component_a; @@ -84,7 +84,7 @@ pub trait ReflectCommandExt { component: Box, ) -> &mut Self; - /// Removes from the entity the component with the given type name registered in [`AppTypeRegistry`] + /// Removes from the entity the component with the given type name registered in [`AppTypeRegistry`]. /// /// Does nothing if the entity does not have a component of the same type, if [`AppTypeRegistry`] /// does not contain the reflection data for the given component, or if the entity does not exist. @@ -181,6 +181,27 @@ impl<'w, 's, 'a> ReflectCommandExt for EntityCommands<'w, 's, 'a> { } } +/// Helper function to add a reflect component to a given entity +fn insert_reflect( + world: &mut World, + entity: Entity, + type_registry: &TypeRegistry, + component: Box, +) { + let type_info = component.type_name(); + let Some(mut entity) = world.get_entity_mut(entity) else { + panic!("error[B0003]: Could not insert a reflected component (of type {}) for entity {:?} because it doesn't exist in this World.", component.type_name(), entity); + + }; + let Some(type_registration) = type_registry.get_with_name(type_info) else { + panic!("Could not get type registration (for component type {}) because it doesn't exist in the TypeRegistry.", component.type_name()); + }; + let Some(reflect_component) = type_registration.data::() else { + panic!("Could not get ReflectComponent data (for component type {}) because it doesn't exist in this TypeRegistration.", component.type_name()); + }; + reflect_component.insert(&mut entity, &*component); +} + /// A [`Command`] that adds the boxed reflect component to an entity using the data in /// [`AppTypeRegistry`]. /// @@ -195,20 +216,7 @@ pub struct InsertReflect { impl Command for InsertReflect { fn apply(self, world: &mut World) { let registry = world.get_resource::().unwrap().clone(); - if let Some(mut entity) = world.get_entity_mut(self.entity) { - let type_info = self.component.type_name(); - if let Some(type_registration) = registry.read().get_with_name(type_info) { - if let Some(reflect_component) = type_registration.data::() { - reflect_component.insert(&mut entity, &*self.component); - } else { - panic!("Could not get ReflectComponent data (for component type {}) because it doesn't exist in this TypeRegistration.", self.component.type_name()); - } - } else { - panic!("Could not get type registration (for component type {}) because it doesn't exist in the TypeRegistry.", self.component.type_name()); - } - } else { - panic!("error[B0003]: Could not insert a reflected component (of type {}) for entity {:?} because it doesn't exist in this World.", self.component.type_name(), self.entity); - } + insert_reflect(world, self.entity, ®istry.read(), self.component); } } @@ -228,24 +236,31 @@ impl> Command for InsertReflectWithRegistry fn apply(self, world: &mut World) { let registry = world.remove_resource::().unwrap(); let registry: &TypeRegistry = registry.as_ref(); - - if let Some(mut entity) = world.get_entity_mut(self.entity) { - let type_info = self.component.type_name(); - if let Some(type_registration) = registry.get_with_name(type_info) { - if let Some(reflect_component) = type_registration.data::() { - reflect_component.insert(&mut entity, &*self.component); - } else { - panic!("Could not get ReflectComponent data (for component type {}) because it doesn't exist in this TypeRegistration.", self.component.type_name()); - } - } else { - panic!("Could not get type registration (for component type {}) because it doesn't exist in the TypeRegistry.", self.component.type_name()); - } - } else { - panic!("error[B0003]: Could not insert a reflected component (of type {}) for entity {:?} because it doesn't exist in this World.", self.component.type_name(), self.entity); - } + insert_reflect(world, self.entity, registry, self.component); } } +/// Helper function to remove a reflect component from a given entity +fn remove_reflect( + world: &mut World, + entity: Entity, + type_registry: &TypeRegistry, + component_type_name: Cow<'static, str>, +) { + let Some(mut entity) = world.get_entity_mut(entity) else { + return; + }; + let Some(type_registration) = type_registry.get_with_name(&component_type_name) else { + return; + + }; + let Some(reflect_component) = type_registration.data::() else { + return; + + }; + reflect_component.remove(&mut entity); +} + /// A [`Command`] that removes the component of the same type as the given component type name from /// the provided entity. /// @@ -261,15 +276,12 @@ pub struct RemoveReflect { impl Command for RemoveReflect { fn apply(self, world: &mut World) { let registry = world.get_resource::().unwrap().clone(); - if let Some(mut entity) = world.get_entity_mut(self.entity) { - if let Some(type_registration) = - registry.read().get_with_name(&self.component_type_name) - { - if let Some(reflect_component) = type_registration.data::() { - reflect_component.remove(&mut entity); - } - } - } + remove_reflect( + world, + self.entity, + ®istry.read(), + self.component_type_name, + ); } } @@ -290,14 +302,7 @@ impl> Command for RemoveReflectWithRegistry fn apply(self, world: &mut World) { let registry = world.remove_resource::().unwrap(); let registry: &TypeRegistry = registry.as_ref(); - - if let Some(mut entity) = world.get_entity_mut(self.entity) { - if let Some(type_registration) = registry.get_with_name(&self.component_type_name) { - if let Some(reflect_component) = type_registration.data::() { - reflect_component.remove(&mut entity); - } - } - } + remove_reflect(world, self.entity, registry, self.component_type_name); } } @@ -308,7 +313,7 @@ mod tests { use crate::system::{Commands, SystemState}; use crate::{self as bevy_ecs, component::Component, world::World}; use bevy_ecs_macros::Resource; - use bevy_reflect::{FromType, Reflect, TypeRegistry}; + use bevy_reflect::{Reflect, TypeRegistry}; #[derive(Resource)] struct TypeRegistryResource { @@ -321,7 +326,7 @@ mod tests { } } - #[derive(Component, Reflect, Default)] + #[derive(Component, Reflect, Default, PartialEq, Eq, Debug)] #[reflect(Component)] struct ComponentA(u32); @@ -330,13 +335,11 @@ mod tests { let mut world = World::new(); let type_registry = AppTypeRegistry::default(); - let mut registry = type_registry.write(); - registry.register::(); - let registration = registry - .get_mut(std::any::TypeId::of::()) - .unwrap(); - registration.insert(>::from_type()); - drop(registry); + { + let mut registry = type_registry.write(); + registry.register::(); + registry.register_type_data::(); + } world.insert_resource(type_registry); let mut system_state: SystemState = SystemState::new(&mut world); @@ -351,8 +354,10 @@ mod tests { .insert_reflect(boxed_reflect_component_a); system_state.apply(&mut world); - assert!(world.entity(entity).get::().is_some()); - assert_eq!(world.entity(entity).get::().unwrap().0, 916); + assert_eq!( + world.entity(entity).get::(), + Some(&ComponentA(916)) + ); } #[test] @@ -364,11 +369,9 @@ mod tests { }; type_registry.type_registry.register::(); - let registration = type_registry + type_registry .type_registry - .get_mut(std::any::TypeId::of::()) - .unwrap(); - registration.insert(>::from_type()); + .register_type_data::(); world.insert_resource(type_registry); let mut system_state: SystemState = SystemState::new(&mut world); @@ -383,8 +386,10 @@ mod tests { .insert_reflect_with_registry::(boxed_reflect_component_a); system_state.apply(&mut world); - assert!(world.entity(entity).get::().is_some()); - assert_eq!(world.entity(entity).get::().unwrap().0, 916); + assert_eq!( + world.entity(entity).get::(), + Some(&ComponentA(916)) + ); } #[test] @@ -392,13 +397,11 @@ mod tests { let mut world = World::new(); let type_registry = AppTypeRegistry::default(); - let mut registry = type_registry.write(); - registry.register::(); - let registration = registry - .get_mut(std::any::TypeId::of::()) - .unwrap(); - registration.insert(>::from_type()); - drop(registry); + { + let mut registry = type_registry.write(); + registry.register::(); + registry.register_type_data::(); + } world.insert_resource(type_registry); let mut system_state: SystemState = SystemState::new(&mut world); @@ -413,7 +416,7 @@ mod tests { .remove_reflect(boxed_reflect_component_a.type_name().to_owned()); system_state.apply(&mut world); - assert!(world.entity(entity).get::().is_none()); + assert_eq!(world.entity(entity).get::(), None); } #[test] @@ -425,11 +428,9 @@ mod tests { }; type_registry.type_registry.register::(); - let registration = type_registry + type_registry .type_registry - .get_mut(std::any::TypeId::of::()) - .unwrap(); - registration.insert(>::from_type()); + .register_type_data::(); world.insert_resource(type_registry); let mut system_state: SystemState = SystemState::new(&mut world); @@ -446,6 +447,6 @@ mod tests { ); system_state.apply(&mut world); - assert!(world.entity(entity).get::().is_none()); + assert_eq!(world.entity(entity).get::(), None); } } From a5355c81bd2b7e2570915a93a715f290419f1184 Mon Sep 17 00:00:00 2001 From: Noah Date: Fri, 25 Aug 2023 23:49:03 -0400 Subject: [PATCH 11/12] Fix with_registry commands removing the resource and not returning it --- crates/bevy_ecs/src/reflect/entity_commands.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/crates/bevy_ecs/src/reflect/entity_commands.rs b/crates/bevy_ecs/src/reflect/entity_commands.rs index 6aa6a0830e43a..552660760d24e 100644 --- a/crates/bevy_ecs/src/reflect/entity_commands.rs +++ b/crates/bevy_ecs/src/reflect/entity_commands.rs @@ -1,3 +1,4 @@ +use crate::prelude::Mut; use crate::reflect::AppTypeRegistry; use crate::system::{Command, EntityCommands, Resource}; use crate::{entity::Entity, reflect::ReflectComponent, world::World}; @@ -190,7 +191,7 @@ fn insert_reflect( ) { let type_info = component.type_name(); let Some(mut entity) = world.get_entity_mut(entity) else { - panic!("error[B0003]: Could not insert a reflected component (of type {}) for entity {:?} because it doesn't exist in this World.", component.type_name(), entity); + panic!("error[B0003]: Could not insert a reflected component (of type {}) for entity {entity:?} because it doesn't exist in this World.", component.type_name()); }; let Some(type_registration) = type_registry.get_with_name(type_info) else { @@ -234,9 +235,10 @@ pub struct InsertReflectWithRegistry> { impl> Command for InsertReflectWithRegistry { fn apply(self, world: &mut World) { - let registry = world.remove_resource::().unwrap(); - let registry: &TypeRegistry = registry.as_ref(); - insert_reflect(world, self.entity, registry, self.component); + world.resource_scope(|world, registry: Mut| { + let registry: &TypeRegistry = registry.as_ref().as_ref(); + insert_reflect(world, self.entity, registry, self.component); + }); } } @@ -300,9 +302,10 @@ pub struct RemoveReflectWithRegistry> { impl> Command for RemoveReflectWithRegistry { fn apply(self, world: &mut World) { - let registry = world.remove_resource::().unwrap(); - let registry: &TypeRegistry = registry.as_ref(); - remove_reflect(world, self.entity, registry, self.component_type_name); + world.resource_scope(|world, registry: Mut| { + let registry: &TypeRegistry = registry.as_ref().as_ref(); + remove_reflect(world, self.entity, registry, self.component_type_name); + }); } } From c6b2b2a88c759c41f6873ad935961e7235d53068 Mon Sep 17 00:00:00 2001 From: Noah Date: Mon, 28 Aug 2023 12:45:24 -0400 Subject: [PATCH 12/12] Format --- crates/bevy_ecs/src/reflect/entity_commands.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/crates/bevy_ecs/src/reflect/entity_commands.rs b/crates/bevy_ecs/src/reflect/entity_commands.rs index 552660760d24e..da9374bbf8a06 100644 --- a/crates/bevy_ecs/src/reflect/entity_commands.rs +++ b/crates/bevy_ecs/src/reflect/entity_commands.rs @@ -192,7 +192,6 @@ fn insert_reflect( let type_info = component.type_name(); let Some(mut entity) = world.get_entity_mut(entity) else { panic!("error[B0003]: Could not insert a reflected component (of type {}) for entity {entity:?} because it doesn't exist in this World.", component.type_name()); - }; let Some(type_registration) = type_registry.get_with_name(type_info) else { panic!("Could not get type registration (for component type {}) because it doesn't exist in the TypeRegistry.", component.type_name()); @@ -254,11 +253,9 @@ fn remove_reflect( }; let Some(type_registration) = type_registry.get_with_name(&component_type_name) else { return; - }; let Some(reflect_component) = type_registration.data::() else { return; - }; reflect_component.remove(&mut entity); }