diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index 0c5950bbb1..33d42b3cb8 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -4,6 +4,7 @@ use crate::{ }; pub use bevy_derive::AppLabel; use bevy_ecs::{ + component::RequiredComponentsError, event::{event_update_system, EventCursor}, intern::Interned, prelude::*, @@ -753,6 +754,260 @@ impl App { self } + /// Registers the given component `R` as a [required component] for `T`. + /// + /// When `T` is added to an entity, `R` and its own required components will also be added + /// if `R` was not already provided. The [`Default`] `constructor` will be used for the creation of `R`. + /// If a custom constructor is desired, use [`App::register_required_components_with`] instead. + /// + /// For the non-panicking version, see [`App::try_register_required_components`]. + /// + /// Note that requirements must currently be registered before `T` is inserted into the world + /// for the first time. Commonly, this is done in plugins. This limitation may be fixed in the future. + /// + /// [required component]: Component#required-components + /// + /// # Panics + /// + /// Panics if `R` is already a directly required component for `T`, or if `T` has ever been added + /// on an entity before the registration. + /// + /// Indirect requirements through other components are allowed. In those cases, any existing requirements + /// will only be overwritten if the new requirement is more specific. + /// + /// # Example + /// + /// ``` + /// # use bevy_app::{App, NoopPluginGroup as MinimalPlugins, Startup}; + /// # use bevy_ecs::prelude::*; + /// #[derive(Component)] + /// struct A; + /// + /// #[derive(Component, Default, PartialEq, Eq, Debug)] + /// struct B(usize); + /// + /// #[derive(Component, Default, PartialEq, Eq, Debug)] + /// struct C(u32); + /// + /// # let mut app = App::new(); + /// # app.add_plugins(MinimalPlugins).add_systems(Startup, setup); + /// // Register B as required by A and C as required by B. + /// app.register_required_components::(); + /// app.register_required_components::(); + /// + /// fn setup(mut commands: Commands) { + /// // This will implicitly also insert B and C with their Default constructors. + /// commands.spawn(A); + /// } + /// + /// fn validate(query: Query<(&A, &B, &C)>) { + /// let (a, b, c) = query.single(); + /// assert_eq!(b, &B(0)); + /// assert_eq!(c, &C(0)); + /// } + /// # app.update(); + /// ``` + pub fn register_required_components( + &mut self, + ) -> &mut Self { + self.world_mut().register_required_components::(); + self + } + + /// Registers the given component `R` as a [required component] for `T`. + /// + /// When `T` is added to an entity, `R` and its own required components will also be added + /// if `R` was not already provided. The given `constructor` will be used for the creation of `R`. + /// If a [`Default`] constructor is desired, use [`App::register_required_components`] instead. + /// + /// For the non-panicking version, see [`App::try_register_required_components_with`]. + /// + /// Note that requirements must currently be registered before `T` is inserted into the world + /// for the first time. Commonly, this is done in plugins. This limitation may be fixed in the future. + /// + /// [required component]: Component#required-components + /// + /// # Panics + /// + /// Panics if `R` is already a directly required component for `T`, or if `T` has ever been added + /// on an entity before the registration. + /// + /// Indirect requirements through other components are allowed. In those cases, any existing requirements + /// will only be overwritten if the new requirement is more specific. + /// + /// # Example + /// + /// ``` + /// # use bevy_app::{App, NoopPluginGroup as MinimalPlugins, Startup}; + /// # use bevy_ecs::prelude::*; + /// #[derive(Component)] + /// struct A; + /// + /// #[derive(Component, Default, PartialEq, Eq, Debug)] + /// struct B(usize); + /// + /// #[derive(Component, Default, PartialEq, Eq, Debug)] + /// struct C(u32); + /// + /// # let mut app = App::new(); + /// # app.add_plugins(MinimalPlugins).add_systems(Startup, setup); + /// // Register B and C as required by A and C as required by B. + /// // A requiring C directly will overwrite the indirect requirement through B. + /// app.register_required_components::(); + /// app.register_required_components_with::(|| C(1)); + /// app.register_required_components_with::(|| C(2)); + /// + /// fn setup(mut commands: Commands) { + /// // This will implicitly also insert B with its Default constructor and C + /// // with the custom constructor defined by A. + /// commands.spawn(A); + /// } + /// + /// fn validate(query: Query<(&A, &B, &C)>) { + /// let (a, b, c) = query.single(); + /// assert_eq!(b, &B(0)); + /// assert_eq!(c, &C(2)); + /// } + /// # app.update(); + /// ``` + pub fn register_required_components_with( + &mut self, + constructor: fn() -> R, + ) -> &mut Self { + self.world_mut() + .register_required_components_with::(constructor); + self + } + + /// Tries to register the given component `R` as a [required component] for `T`. + /// + /// When `T` is added to an entity, `R` and its own required components will also be added + /// if `R` was not already provided. The [`Default`] `constructor` will be used for the creation of `R`. + /// If a custom constructor is desired, use [`App::register_required_components_with`] instead. + /// + /// For the panicking version, see [`App::register_required_components`]. + /// + /// Note that requirements must currently be registered before `T` is inserted into the world + /// for the first time. Commonly, this is done in plugins. This limitation may be fixed in the future. + /// + /// [required component]: Component#required-components + /// + /// # Errors + /// + /// Returns a [`RequiredComponentsError`] if `R` is already a directly required component for `T`, or if `T` has ever been added + /// on an entity before the registration. + /// + /// Indirect requirements through other components are allowed. In those cases, any existing requirements + /// will only be overwritten if the new requirement is more specific. + /// + /// # Example + /// + /// ``` + /// # use bevy_app::{App, NoopPluginGroup as MinimalPlugins, Startup}; + /// # use bevy_ecs::prelude::*; + /// #[derive(Component)] + /// struct A; + /// + /// #[derive(Component, Default, PartialEq, Eq, Debug)] + /// struct B(usize); + /// + /// #[derive(Component, Default, PartialEq, Eq, Debug)] + /// struct C(u32); + /// + /// # let mut app = App::new(); + /// # app.add_plugins(MinimalPlugins).add_systems(Startup, setup); + /// // Register B as required by A and C as required by B. + /// app.register_required_components::(); + /// app.register_required_components::(); + /// + /// // Duplicate registration! This will fail. + /// assert!(app.try_register_required_components::().is_err()); + /// + /// fn setup(mut commands: Commands) { + /// // This will implicitly also insert B and C with their Default constructors. + /// commands.spawn(A); + /// } + /// + /// fn validate(query: Query<(&A, &B, &C)>) { + /// let (a, b, c) = query.single(); + /// assert_eq!(b, &B(0)); + /// assert_eq!(c, &C(0)); + /// } + /// # app.update(); + /// ``` + pub fn try_register_required_components( + &mut self, + ) -> Result<(), RequiredComponentsError> { + self.world_mut().try_register_required_components::() + } + + /// Tries to register the given component `R` as a [required component] for `T`. + /// + /// When `T` is added to an entity, `R` and its own required components will also be added + /// if `R` was not already provided. The given `constructor` will be used for the creation of `R`. + /// If a [`Default`] constructor is desired, use [`App::register_required_components`] instead. + /// + /// For the panicking version, see [`App::register_required_components_with`]. + /// + /// Note that requirements must currently be registered before `T` is inserted into the world + /// for the first time. Commonly, this is done in plugins. This limitation may be fixed in the future. + /// + /// [required component]: Component#required-components + /// + /// # Errors + /// + /// Returns a [`RequiredComponentsError`] if `R` is already a directly required component for `T`, or if `T` has ever been added + /// on an entity before the registration. + /// + /// Indirect requirements through other components are allowed. In those cases, any existing requirements + /// will only be overwritten if the new requirement is more specific. + /// + /// # Example + /// + /// ``` + /// # use bevy_app::{App, NoopPluginGroup as MinimalPlugins, Startup}; + /// # use bevy_ecs::prelude::*; + /// #[derive(Component)] + /// struct A; + /// + /// #[derive(Component, Default, PartialEq, Eq, Debug)] + /// struct B(usize); + /// + /// #[derive(Component, Default, PartialEq, Eq, Debug)] + /// struct C(u32); + /// + /// # let mut app = App::new(); + /// # app.add_plugins(MinimalPlugins).add_systems(Startup, setup); + /// // Register B and C as required by A and C as required by B. + /// // A requiring C directly will overwrite the indirect requirement through B. + /// app.register_required_components::(); + /// app.register_required_components_with::(|| C(1)); + /// app.register_required_components_with::(|| C(2)); + /// + /// // Duplicate registration! Even if the constructors were different, this would fail. + /// assert!(app.try_register_required_components_with::(|| C(1)).is_err()); + /// + /// fn setup(mut commands: Commands) { + /// // This will implicitly also insert B with its Default constructor and C + /// // with the custom constructor defined by A. + /// commands.spawn(A); + /// } + /// + /// fn validate(query: Query<(&A, &B, &C)>) { + /// let (a, b, c) = query.single(); + /// assert_eq!(b, &B(0)); + /// assert_eq!(c, &C(2)); + /// } + /// # app.update(); + /// ``` + pub fn try_register_required_components_with( + &mut self, + constructor: fn() -> R, + ) -> Result<(), RequiredComponentsError> { + self.world_mut() + .try_register_required_components_with::(constructor) + } + /// Returns a reference to the [`World`]. pub fn world(&self) -> &World { self.main().world() diff --git a/crates/bevy_diagnostic/src/system_information_diagnostics_plugin.rs b/crates/bevy_diagnostic/src/system_information_diagnostics_plugin.rs index 9037c6a8f8..b108f34f3e 100644 --- a/crates/bevy_diagnostic/src/system_information_diagnostics_plugin.rs +++ b/crates/bevy_diagnostic/src/system_information_diagnostics_plugin.rs @@ -59,11 +59,9 @@ pub struct SystemInfo { not(feature = "dynamic_linking") ))] pub mod internal { + use alloc::sync::Arc; use bevy_ecs::{prelude::ResMut, system::Local}; - use std::{ - sync::{Arc, Mutex}, - time::Instant, - }; + use std::{sync::Mutex, time::Instant}; use bevy_app::{App, First, Startup, Update}; use bevy_ecs::system::Resource; diff --git a/crates/bevy_ecs/macros/src/component.rs b/crates/bevy_ecs/macros/src/component.rs index 3ebd64736a..de41596f97 100644 --- a/crates/bevy_ecs/macros/src/component.rs +++ b/crates/bevy_ecs/macros/src/component.rs @@ -82,15 +82,31 @@ pub fn derive_component(input: TokenStream) -> TokenStream { for require in requires { let ident = &require.path; register_recursive_requires.push(quote! { - <#ident as Component>::register_required_components(components, storages, required_components); + <#ident as Component>::register_required_components( + requiree, + components, + storages, + required_components, + inheritance_depth + 1 + ); }); if let Some(func) = &require.func { register_required.push(quote! { - required_components.register(components, storages, || { let x: #ident = #func().into(); x }); + components.register_required_components_manual::( + storages, + required_components, + || { let x: #ident = #func().into(); x }, + inheritance_depth + ); }); } else { register_required.push(quote! { - required_components.register(components, storages, <#ident as Default>::default); + components.register_required_components_manual::( + storages, + required_components, + <#ident as Default>::default, + inheritance_depth + ); }); } } @@ -117,9 +133,11 @@ pub fn derive_component(input: TokenStream) -> TokenStream { impl #impl_generics #bevy_ecs_path::component::Component for #struct_name #type_generics #where_clause { const STORAGE_TYPE: #bevy_ecs_path::component::StorageType = #storage; fn register_required_components( + requiree: #bevy_ecs_path::component::ComponentId, components: &mut #bevy_ecs_path::component::Components, storages: &mut #bevy_ecs_path::storage::Storages, - required_components: &mut #bevy_ecs_path::component::RequiredComponents + required_components: &mut #bevy_ecs_path::component::RequiredComponents, + inheritance_depth: u16, ) { #(#register_required)* #(#register_recursive_requires)* diff --git a/crates/bevy_ecs/src/bundle.rs b/crates/bevy_ecs/src/bundle.rs index bbe114a2fe..7a23ac3f11 100644 --- a/crates/bevy_ecs/src/bundle.rs +++ b/crates/bevy_ecs/src/bundle.rs @@ -224,7 +224,14 @@ unsafe impl Bundle for C { storages: &mut Storages, required_components: &mut RequiredComponents, ) { - ::register_required_components(components, storages, required_components); + let component_id = components.register_component::(storages); + ::register_required_components( + component_id, + components, + storages, + required_components, + 0, + ); } fn get_component_ids(components: &Components, ids: &mut impl FnMut(Option)) { @@ -412,7 +419,7 @@ impl BundleInfo { // This adds required components to the component_ids list _after_ using that list to remove explicitly provided // components. This ordering is important! component_ids.push(component_id); - v + v.constructor }) .collect(); diff --git a/crates/bevy_ecs/src/component.rs b/crates/bevy_ecs/src/component.rs index d461fa4ba7..121d49a291 100644 --- a/crates/bevy_ecs/src/component.rs +++ b/crates/bevy_ecs/src/component.rs @@ -6,6 +6,7 @@ use crate::{ bundle::BundleInfo, change_detection::MAX_CHANGE_AGE, entity::Entity, + query::DebugCheckedUnwrap, storage::{SparseSetIndex, SparseSets, Storages, Table, TableRow}, system::{Local, Resource, SystemParam}, world::{DeferredWorld, FromWorld, World}, @@ -15,7 +16,7 @@ pub use bevy_ecs_macros::Component; use bevy_ptr::{OwningPtr, UnsafeCellDeref}; #[cfg(feature = "bevy_reflect")] use bevy_reflect::Reflect; -use bevy_utils::{HashMap, TypeIdMap}; +use bevy_utils::{HashMap, HashSet, TypeIdMap}; #[cfg(feature = "track_change_detection")] use core::panic::Location; use core::{ @@ -26,6 +27,7 @@ use core::{ marker::PhantomData, mem::needs_drop, }; +use thiserror::Error; /// A data type that can be used to store data for an [entity]. /// @@ -232,6 +234,48 @@ use core::{ /// 1. Specifying a required component constructor for Foo directly on a spawned component Bar will result in that constructor being used (and overriding existing constructors lower in the inheritance tree). This is the classic "inheritance override" behavior people expect. /// 2. For cases where "multiple inheritance" results in constructor clashes, Components should be listed in "importance order". List a component earlier in the requirement list to initialize its inheritance tree earlier. /// +/// ## Registering required components at runtime +/// +/// In most cases, required components should be registered using the `require` attribute as shown above. +/// However, in some cases, it may be useful to register required components at runtime. +/// +/// This can be done through [`World::register_required_components`] or [`World::register_required_components_with`] +/// for the [`Default`] and custom constructors respectively: +/// +/// ``` +/// # use bevy_ecs::prelude::*; +/// #[derive(Component)] +/// struct A; +/// +/// #[derive(Component, Default, PartialEq, Eq, Debug)] +/// struct B(usize); +/// +/// #[derive(Component, PartialEq, Eq, Debug)] +/// struct C(u32); +/// +/// # let mut world = World::default(); +/// // Register B as required by A and C as required by B. +/// world.register_required_components::(); +/// world.register_required_components_with::(|| C(2)); +/// +/// // This will implicitly also insert B with its Default constructor +/// // and C with the custom constructor defined by B. +/// let id = world.spawn(A).id(); +/// assert_eq!(&B(0), world.entity(id).get::().unwrap()); +/// assert_eq!(&C(2), world.entity(id).get::().unwrap()); +/// ``` +/// +/// Similar rules as before apply to duplicate requires fer a given type at different levels +/// of the inheritance tree. `A` requiring `C` directly would take precedence over indirectly +/// requiring it through `A` requiring `B` and `B` requiring `C`. +/// +/// Unlike with the `require` attribute, directly requiring the same component multiple times +/// for the same component will result in a panic. This is done to prevent conflicting constructors +/// and confusing ordering dependencies. +/// +/// Note that requirements must currently be registered before the requiring component is inserted +/// into the world for the first time. Registering requirements after this will lead to a panic. +/// /// # Adding component's hooks /// /// See [`ComponentHooks`] for a detailed explanation of component's hooks. @@ -339,9 +383,11 @@ pub trait Component: Send + Sync + 'static { /// Registers required components. fn register_required_components( + _component_id: ComponentId, _components: &mut Components, _storages: &mut Storages, _required_components: &mut RequiredComponents, + _inheritance_depth: u16, ) { } } @@ -555,6 +601,7 @@ pub struct ComponentInfo { descriptor: ComponentDescriptor, hooks: ComponentHooks, required_components: RequiredComponents, + required_by: HashSet, } impl ComponentInfo { @@ -615,6 +662,7 @@ impl ComponentInfo { descriptor, hooks: Default::default(), required_components: Default::default(), + required_by: Default::default(), } } @@ -866,7 +914,7 @@ impl Components { }; if registered { let mut required_components = RequiredComponents::default(); - T::register_required_components(self, storages, &mut required_components); + T::register_required_components(id, self, storages, &mut required_components, 0); let info = &mut self.components[id.index()]; T::register_component_hooks(&mut info.hooks); info.required_components = required_components; @@ -952,6 +1000,255 @@ impl Components { self.components.get_mut(id.0).map(|info| &mut info.hooks) } + #[inline] + pub(crate) fn get_required_components_mut( + &mut self, + id: ComponentId, + ) -> Option<&mut RequiredComponents> { + self.components + .get_mut(id.0) + .map(|info| &mut info.required_components) + } + + /// Registers the given component `R` and [required components] inherited from it as required by `T`. + /// + /// When `T` is added to an entity, `R` will also be added if it was not already provided. + /// The given `constructor` will be used for the creation of `R`. + /// + /// [required components]: Component#required-components + /// + /// # Safety + /// + /// The given component IDs `required` and `requiree` must be valid. + /// + /// # Errors + /// + /// Returns a [`RequiredComponentsError`] if the `required` component is already a directly required component for the `requiree`. + /// + /// Indirect requirements through other components are allowed. In those cases, the more specific + /// registration will be used. + pub(crate) unsafe fn register_required_components( + &mut self, + required: ComponentId, + requiree: ComponentId, + constructor: fn() -> R, + ) -> Result<(), RequiredComponentsError> { + // SAFETY: The caller ensures that the `requiree` is valid. + let required_components = unsafe { + self.get_required_components_mut(requiree) + .debug_checked_unwrap() + }; + + // Cannot directly require the same component twice. + if required_components + .0 + .get(&required) + .is_some_and(|c| c.inheritance_depth == 0) + { + return Err(RequiredComponentsError::DuplicateRegistration( + requiree, required, + )); + } + + // Register the required component for the requiree. + // This is a direct requirement with a depth of `0`. + required_components.register_by_id(required, constructor, 0); + + // Add the requiree to the list of components that require the required component. + // SAFETY: The component is in the list of required components, so it must exist already. + let required_by = unsafe { self.get_required_by_mut(required).debug_checked_unwrap() }; + required_by.insert(requiree); + + // SAFETY: The caller ensures that the `requiree` and `required` components are valid. + let inherited_requirements = + unsafe { self.register_inherited_required_components(requiree, required) }; + + // Propagate the new required components up the chain to all components that require the requiree. + if let Some(required_by) = self.get_required_by(requiree).cloned() { + for &required_by_id in required_by.iter() { + // SAFETY: The component is in the list of required components, so it must exist already. + let required_components = unsafe { + self.get_required_components_mut(required_by_id) + .debug_checked_unwrap() + }; + + // Register the original required component for the requiree. + // The inheritance depth is `1` since this is a component required by the original requiree. + required_components.register_by_id(required, constructor, 1); + + for (component_id, component) in inherited_requirements.iter() { + // Register the required component. + // The inheritance depth is increased by `1` since this is a component required by the original required component. + // SAFETY: Component ID and constructor match the ones on the original requiree. + // The original requiree is responsible for making sure the registration is safe. + unsafe { + required_components.register_dynamic( + *component_id, + component.constructor.clone(), + component.inheritance_depth + 1, + ); + }; + } + } + } + + Ok(()) + } + + /// Registers the components inherited from `required` for the given `requiree`, + /// returning the requirements in a list. + /// + /// # Safety + /// + /// The given component IDs `requiree` and `required` must be valid. + unsafe fn register_inherited_required_components( + &mut self, + requiree: ComponentId, + required: ComponentId, + ) -> Vec<(ComponentId, RequiredComponent)> { + // Get required components inherited from the `required` component. + // SAFETY: The caller ensures that the `required` component is valid. + let required_component_info = unsafe { self.get_info(required).debug_checked_unwrap() }; + let inherited_requirements: Vec<(ComponentId, RequiredComponent)> = required_component_info + .required_components() + .0 + .iter() + .map(|(component_id, required_component)| { + ( + *component_id, + RequiredComponent { + constructor: required_component.constructor.clone(), + // Add `1` to the inheritance depth since this will be registered + // for the component that requires `required`. + inheritance_depth: required_component.inheritance_depth + 1, + }, + ) + }) + .collect(); + + // Register the new required components. + for (component_id, component) in inherited_requirements.iter().cloned() { + // SAFETY: The caller ensures that the `requiree` is valid. + let required_components = unsafe { + self.get_required_components_mut(requiree) + .debug_checked_unwrap() + }; + + // Register the required component for the requiree. + // SAFETY: Component ID and constructor match the ones on the original requiree. + unsafe { + required_components.register_dynamic( + component_id, + component.constructor, + component.inheritance_depth, + ); + }; + + // Add the requiree to the list of components that require the required component. + // SAFETY: The caller ensures that the required components are valid. + let required_by = unsafe { + self.get_required_by_mut(component_id) + .debug_checked_unwrap() + }; + required_by.insert(requiree); + } + + inherited_requirements + } + + // NOTE: This should maybe be private, but it is currently public so that `bevy_ecs_macros` can use it. + // We can't directly move this there either, because this uses `Components::get_required_by_mut`, + // which is private, and could be equally risky to expose to users. + /// Registers the given component `R` as a [required component] for `T`, + /// and adds `T` to the list of requirees for `R`. + /// + /// The given `inheritance_depth` determines how many levels of inheritance deep the requirement is. + /// A direct requirement has a depth of `0`, and each level of inheritance increases the depth by `1`. + /// Lower depths are more specific requirements, and can override existing less specific registrations. + /// + /// This method does *not* recursively register required components for components required by `R`, + /// nor does it register them for components that require `T`. + /// + /// Only use this method if you know what you are doing. In most cases, you should instead use [`World::register_required_components`], + /// or the equivalent method in `bevy_app::App`. + /// + /// [required component]: Component#required-components + #[doc(hidden)] + pub fn register_required_components_manual( + &mut self, + storages: &mut Storages, + required_components: &mut RequiredComponents, + constructor: fn() -> R, + inheritance_depth: u16, + ) { + let requiree = self.register_component::(storages); + let required = self.register_component::(storages); + + // SAFETY: We just created the components. + unsafe { + self.register_required_components_manual_unchecked::( + requiree, + required, + required_components, + constructor, + inheritance_depth, + ); + } + } + + /// Registers the given component `R` as a [required component] for `T`, + /// and adds `T` to the list of requirees for `R`. + /// + /// The given `inheritance_depth` determines how many levels of inheritance deep the requirement is. + /// A direct requirement has a depth of `0`, and each level of inheritance increases the depth by `1`. + /// Lower depths are more specific requirements, and can override existing less specific registrations. + /// + /// This method does *not* recursively register required components for components required by `R`, + /// nor does it register them for components that require `T`. + /// + /// [required component]: Component#required-components + /// + /// # Safety + /// + /// The given component IDs `required` and `requiree` must be valid. + pub(crate) unsafe fn register_required_components_manual_unchecked( + &mut self, + requiree: ComponentId, + required: ComponentId, + required_components: &mut RequiredComponents, + constructor: fn() -> R, + inheritance_depth: u16, + ) { + // Components cannot require themselves. + if required == requiree { + return; + } + + // Register the required component `R` for the requiree. + required_components.register_by_id(required, constructor, inheritance_depth); + + // Add the requiree to the list of components that require `R`. + // SAFETY: The caller ensures that the component ID is valid. + // Assuming it is valid, the component is in the list of required components, so it must exist already. + let required_by = unsafe { self.get_required_by_mut(required).debug_checked_unwrap() }; + required_by.insert(requiree); + } + + #[inline] + pub(crate) fn get_required_by(&self, id: ComponentId) -> Option<&HashSet> { + self.components.get(id.0).map(|info| &info.required_by) + } + + #[inline] + pub(crate) fn get_required_by_mut( + &mut self, + id: ComponentId, + ) -> Option<&mut HashSet> { + self.components + .get_mut(id.0) + .map(|info| &mut info.required_by) + } + /// Type-erased equivalent of [`Components::component_id()`]. #[inline] pub fn get_id(&self, type_id: TypeId) -> Option { @@ -1325,6 +1622,18 @@ impl FromWorld for InitComponentId { } } +/// An error returned when the registration of a required component fails. +#[derive(Error, Debug)] +#[non_exhaustive] +pub enum RequiredComponentsError { + /// The component is already a directly required component for the requiree. + #[error("Component {0:?} already directly requires component {1:?}")] + DuplicateRegistration(ComponentId, ComponentId), + /// An archetype with the component that requires other components already exists + #[error("An archetype with the component {0:?} that requires other components already exists")] + ArchetypeExists(ComponentId), +} + /// A Required Component constructor. See [`Component`] for details. #[cfg(feature = "track_change_detection")] #[derive(Clone)] @@ -1370,11 +1679,30 @@ impl RequiredComponentConstructor { } } +/// Metadata associated with a required component. See [`Component`] for details. +#[derive(Clone)] +pub struct RequiredComponent { + /// The constructor used for the required component. + pub constructor: RequiredComponentConstructor, + + /// The depth of the component requirement in the requirement hierarchy for this component. + /// This is used for determining which constructor is used in cases where there are duplicate requires. + /// + /// For example, consider the inheritance tree `X -> Y -> Z`, where `->` indicates a requirement. + /// `X -> Y` and `Y -> Z` are direct requirements with a depth of 0, while `Z` is only indirectly + /// required for `X` with a depth of `1`. + /// + /// In cases where there are multiple conflicting requirements with the same depth, a higher priority + /// will be given to components listed earlier in the `require` attribute, or to the latest added requirement + /// if registered at runtime. + pub inheritance_depth: u16, +} + /// The collection of metadata for components that are required for a given component. /// /// For more information, see the "Required Components" section of [`Component`]. #[derive(Default, Clone)] -pub struct RequiredComponents(pub(crate) HashMap); +pub struct RequiredComponents(pub(crate) HashMap); impl Debug for RequiredComponents { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { @@ -1385,8 +1713,10 @@ impl Debug for RequiredComponents { } impl RequiredComponents { - /// Registers a required component. If the component is already registered, the new registration - /// passed in the arguments will be ignored. + /// Registers a required component. + /// + /// If the component is already registered, it will be overwritten if the given inheritance depth + /// is smaller than the depth of the existing registration. Otherwise, the new registration will be ignored. /// /// # Safety /// @@ -1398,19 +1728,48 @@ impl RequiredComponents { &mut self, component_id: ComponentId, constructor: RequiredComponentConstructor, + inheritance_depth: u16, ) { - self.0.entry(component_id).or_insert(constructor); + self.0 + .entry(component_id) + .and_modify(|component| { + if component.inheritance_depth > inheritance_depth { + // New registration is more specific than existing requirement + component.constructor = constructor.clone(); + component.inheritance_depth = inheritance_depth; + } + }) + .or_insert(RequiredComponent { + constructor, + inheritance_depth, + }); } - /// Registers a required component. If the component is already registered, the new registration - /// passed in the arguments will be ignored. + /// Registers a required component. + /// + /// If the component is already registered, it will be overwritten if the given inheritance depth + /// is smaller than the depth of the existing registration. Otherwise, the new registration will be ignored. pub fn register( &mut self, components: &mut Components, storages: &mut Storages, constructor: fn() -> C, + inheritance_depth: u16, ) { let component_id = components.register_component::(storages); + self.register_by_id(component_id, constructor, inheritance_depth); + } + + /// Registers the [`Component`] with the given ID as required if it exists. + /// + /// If the component is already registered, it will be overwritten if the given inheritance depth + /// is smaller than the depth of the existing registration. Otherwise, the new registration will be ignored. + pub fn register_by_id( + &mut self, + component_id: ComponentId, + constructor: fn() -> C, + inheritance_depth: u16, + ) { let erased: RequiredComponentConstructor = RequiredComponentConstructor(Arc::new( move |table, sparse_sets, @@ -1445,7 +1804,7 @@ impl RequiredComponents { // `erased` initializes a component for `component_id` in such a way that // matches the storage type of the component. It only uses the given `table_row` or `Entity` to // initialize the storage corresponding to the given entity. - unsafe { self.register_dynamic(component_id, erased) }; + unsafe { self.register_dynamic(component_id, erased, inheritance_depth) }; } /// Iterates the ids of all required components. This includes recursive required components. diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index 550e9a20e3..4dda0d4ea9 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -82,6 +82,7 @@ pub mod prelude { #[cfg(test)] mod tests { use crate as bevy_ecs; + use crate::component::{RequiredComponents, RequiredComponentsError}; use crate::{ bundle::Bundle, change_detection::Ref, @@ -92,7 +93,7 @@ mod tests { system::Resource, world::{EntityMut, EntityRef, Mut, World}, }; - use alloc::sync::Arc; + use alloc::{sync::Arc, vec}; use bevy_ecs_macros::{VisitEntities, VisitEntitiesMut}; use bevy_tasks::{ComputeTaskPool, TaskPool}; use bevy_utils::HashSet; @@ -2028,6 +2029,259 @@ mod tests { assert!(e.contains::()); } + #[test] + fn runtime_required_components() { + // Same as `required_components` test but with runtime registration + + #[derive(Component)] + struct X; + + #[derive(Component)] + struct Y { + value: String, + } + + #[derive(Component)] + struct Z(u32); + + impl Default for Y { + fn default() -> Self { + Self { + value: "hello".to_string(), + } + } + } + + let mut world = World::new(); + + world.register_required_components::(); + world.register_required_components_with::(|| Z(7)); + + let id = world.spawn(X).id(); + + assert_eq!( + "hello", + world.entity(id).get::().unwrap().value, + "Y should have the default value" + ); + assert_eq!( + 7, + world.entity(id).get::().unwrap().0, + "Z should have the value provided by the constructor defined in Y" + ); + + let id = world + .spawn(( + X, + Y { + value: "foo".to_string(), + }, + )) + .id(); + assert_eq!( + "foo", + world.entity(id).get::().unwrap().value, + "Y should have the manually provided value" + ); + assert_eq!( + 7, + world.entity(id).get::().unwrap().0, + "Z should have the value provided by the constructor defined in Y" + ); + + let id = world.spawn((X, Z(8))).id(); + assert_eq!( + "hello", + world.entity(id).get::().unwrap().value, + "Y should have the default value" + ); + assert_eq!( + 8, + world.entity(id).get::().unwrap().0, + "Z should have the manually provided value" + ); + } + + #[test] + fn runtime_required_components_override_1() { + #[derive(Component)] + struct X; + + #[derive(Component, Default)] + struct Y; + + #[derive(Component)] + struct Z(u32); + + let mut world = World::new(); + + // - X requires Y with default constructor + // - Y requires Z with custom constructor + // - X requires Z with custom constructor (more specific than X -> Y -> Z) + world.register_required_components::(); + world.register_required_components_with::(|| Z(5)); + world.register_required_components_with::(|| Z(7)); + + let id = world.spawn(X).id(); + + assert_eq!( + 7, + world.entity(id).get::().unwrap().0, + "Z should have the value provided by the constructor defined in X" + ); + } + + #[test] + fn runtime_required_components_override_2() { + // Same as `runtime_required_components_override_1` test but with different registration order + + #[derive(Component)] + struct X; + + #[derive(Component, Default)] + struct Y; + + #[derive(Component)] + struct Z(u32); + + let mut world = World::new(); + + // - X requires Y with default constructor + // - X requires Z with custom constructor (more specific than X -> Y -> Z) + // - Y requires Z with custom constructor + world.register_required_components::(); + world.register_required_components_with::(|| Z(7)); + world.register_required_components_with::(|| Z(5)); + + let id = world.spawn(X).id(); + + assert_eq!( + 7, + world.entity(id).get::().unwrap().0, + "Z should have the value provided by the constructor defined in X" + ); + } + + #[test] + fn runtime_required_components_existing_archetype() { + #[derive(Component)] + struct X; + + #[derive(Component, Default)] + struct Y; + + let mut world = World::new(); + + // Registering required components after the archetype has already been created should panic. + // This may change in the future. + world.spawn(X); + assert!(matches!( + world.try_register_required_components::(), + Err(RequiredComponentsError::ArchetypeExists(_)) + )); + } + + #[test] + fn runtime_required_components_fail_with_duplicate() { + #[derive(Component)] + #[require(Y)] + struct X; + + #[derive(Component, Default)] + struct Y; + + let mut world = World::new(); + + // This should fail: Tried to register Y as a requirement for X, but the requirement already exists. + assert!(matches!( + world.try_register_required_components::(), + Err(RequiredComponentsError::DuplicateRegistration(_, _)) + )); + } + + #[test] + fn required_components_inheritance_depth() { + // Test that inheritance depths are computed correctly for requirements. + // + // Requirements with `require` attribute: + // + // A -> B -> C + // 0 1 + // + // Runtime requirements: + // + // X -> A -> B -> C + // 0 1 2 + // + // X -> Y -> Z -> B -> C + // 0 1 2 3 + + #[derive(Component, Default)] + #[require(B)] + struct A; + + #[derive(Component, Default)] + #[require(C)] + struct B; + + #[derive(Component, Default)] + struct C; + + #[derive(Component, Default)] + struct X; + + #[derive(Component, Default)] + struct Y; + + #[derive(Component, Default)] + struct Z; + + let mut world = World::new(); + + let a = world.register_component::(); + let b = world.register_component::(); + let c = world.register_component::(); + let y = world.register_component::(); + let z = world.register_component::(); + + world.register_required_components::(); + world.register_required_components::(); + world.register_required_components::(); + world.register_required_components::(); + + world.spawn(X); + + let required_a = world.get_required_components::().unwrap(); + let required_b = world.get_required_components::().unwrap(); + let required_c = world.get_required_components::().unwrap(); + let required_x = world.get_required_components::().unwrap(); + let required_y = world.get_required_components::().unwrap(); + let required_z = world.get_required_components::().unwrap(); + + /// Returns the component IDs and inheritance depths of the required components + /// in ascending order based on the component ID. + fn to_vec(required: &RequiredComponents) -> Vec<(ComponentId, u16)> { + let mut vec = required + .0 + .iter() + .map(|(id, component)| (*id, component.inheritance_depth)) + .collect::>(); + vec.sort_by_key(|(id, _)| *id); + vec + } + + // Check that the inheritance depths are correct for each component. + assert_eq!(to_vec(required_a), vec![(b, 0), (c, 1)]); + assert_eq!(to_vec(required_b), vec![(c, 0)]); + assert_eq!(to_vec(required_c), vec![]); + assert_eq!( + to_vec(required_x), + vec![(a, 0), (b, 1), (c, 2), (y, 0), (z, 1)] + ); + assert_eq!(to_vec(required_y), vec![(b, 1), (c, 2), (z, 0)]); + assert_eq!(to_vec(required_z), vec![(b, 0), (c, 1)]); + } + // These structs are primarily compilation tests to test the derive macros. Because they are // never constructed, we have to manually silence the `dead_code` lint. #[allow(dead_code)] diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 554bb607a5..81730be65d 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -31,7 +31,7 @@ use crate::{ change_detection::{MutUntyped, TicksMut}, component::{ Component, ComponentDescriptor, ComponentHooks, ComponentId, ComponentInfo, ComponentTicks, - Components, Tick, + Components, RequiredComponents, RequiredComponentsError, Tick, }, entity::{AllocAtWithoutReplacement, Entities, Entity, EntityHashSet, EntityLocation}, event::{Event, EventId, Events, SendBatchIds}, @@ -287,6 +287,245 @@ impl World { self.components.get_hooks_mut(id) } + /// Registers the given component `R` as a [required component] for `T`. + /// + /// When `T` is added to an entity, `R` and its own required components will also be added + /// if `R` was not already provided. The [`Default`] `constructor` will be used for the creation of `R`. + /// If a custom constructor is desired, use [`World::register_required_components_with`] instead. + /// + /// For the non-panicking version, see [`World::try_register_required_components`]. + /// + /// Note that requirements must currently be registered before `T` is inserted into the world + /// for the first time. This limitation may be fixed in the future. + /// + /// [required component]: Component#required-components + /// + /// # Panics + /// + /// Panics if `R` is already a directly required component for `T`, or if `T` has ever been added + /// on an entity before the registration. + /// + /// Indirect requirements through other components are allowed. In those cases, any existing requirements + /// will only be overwritten if the new requirement is more specific. + /// + /// # Example + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// #[derive(Component)] + /// struct A; + /// + /// #[derive(Component, Default, PartialEq, Eq, Debug)] + /// struct B(usize); + /// + /// #[derive(Component, Default, PartialEq, Eq, Debug)] + /// struct C(u32); + /// + /// # let mut world = World::default(); + /// // Register B as required by A and C as required by B. + /// world.register_required_components::(); + /// world.register_required_components::(); + /// + /// // This will implicitly also insert B and C with their Default constructors. + /// let id = world.spawn(A).id(); + /// assert_eq!(&B(0), world.entity(id).get::().unwrap()); + /// assert_eq!(&C(0), world.entity(id).get::().unwrap()); + /// ``` + pub fn register_required_components(&mut self) { + self.try_register_required_components::().unwrap(); + } + + /// Registers the given component `R` as a [required component] for `T`. + /// + /// When `T` is added to an entity, `R` and its own required components will also be added + /// if `R` was not already provided. The given `constructor` will be used for the creation of `R`. + /// If a [`Default`] constructor is desired, use [`World::register_required_components`] instead. + /// + /// For the non-panicking version, see [`World::try_register_required_components_with`]. + /// + /// Note that requirements must currently be registered before `T` is inserted into the world + /// for the first time. This limitation may be fixed in the future. + /// + /// [required component]: Component#required-components + /// + /// # Panics + /// + /// Panics if `R` is already a directly required component for `T`, or if `T` has ever been added + /// on an entity before the registration. + /// + /// Indirect requirements through other components are allowed. In those cases, any existing requirements + /// will only be overwritten if the new requirement is more specific. + /// + /// # Example + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// #[derive(Component)] + /// struct A; + /// + /// #[derive(Component, Default, PartialEq, Eq, Debug)] + /// struct B(usize); + /// + /// #[derive(Component, PartialEq, Eq, Debug)] + /// struct C(u32); + /// + /// # let mut world = World::default(); + /// // Register B and C as required by A and C as required by B. + /// // A requiring C directly will overwrite the indirect requirement through B. + /// world.register_required_components::(); + /// world.register_required_components_with::(|| C(1)); + /// world.register_required_components_with::(|| C(2)); + /// + /// // This will implicitly also insert B with its Default constructor and C + /// // with the custom constructor defined by A. + /// let id = world.spawn(A).id(); + /// assert_eq!(&B(0), world.entity(id).get::().unwrap()); + /// assert_eq!(&C(2), world.entity(id).get::().unwrap()); + /// ``` + pub fn register_required_components_with( + &mut self, + constructor: fn() -> R, + ) { + self.try_register_required_components_with::(constructor) + .unwrap(); + } + + /// Tries to register the given component `R` as a [required component] for `T`. + /// + /// When `T` is added to an entity, `R` and its own required components will also be added + /// if `R` was not already provided. The [`Default`] `constructor` will be used for the creation of `R`. + /// If a custom constructor is desired, use [`World::register_required_components_with`] instead. + /// + /// For the panicking version, see [`World::register_required_components`]. + /// + /// Note that requirements must currently be registered before `T` is inserted into the world + /// for the first time. This limitation may be fixed in the future. + /// + /// [required component]: Component#required-components + /// + /// # Errors + /// + /// Returns a [`RequiredComponentsError`] if `R` is already a directly required component for `T`, or if `T` has ever been added + /// on an entity before the registration. + /// + /// Indirect requirements through other components are allowed. In those cases, any existing requirements + /// will only be overwritten if the new requirement is more specific. + /// + /// # Example + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// #[derive(Component)] + /// struct A; + /// + /// #[derive(Component, Default, PartialEq, Eq, Debug)] + /// struct B(usize); + /// + /// #[derive(Component, Default, PartialEq, Eq, Debug)] + /// struct C(u32); + /// + /// # let mut world = World::default(); + /// // Register B as required by A and C as required by B. + /// world.register_required_components::(); + /// world.register_required_components::(); + /// + /// // Duplicate registration! This will fail. + /// assert!(world.try_register_required_components::().is_err()); + /// + /// // This will implicitly also insert B and C with their Default constructors. + /// let id = world.spawn(A).id(); + /// assert_eq!(&B(0), world.entity(id).get::().unwrap()); + /// assert_eq!(&C(0), world.entity(id).get::().unwrap()); + /// ``` + pub fn try_register_required_components( + &mut self, + ) -> Result<(), RequiredComponentsError> { + self.try_register_required_components_with::(R::default) + } + + /// Tries to register the given component `R` as a [required component] for `T`. + /// + /// When `T` is added to an entity, `R` and its own required components will also be added + /// if `R` was not already provided. The given `constructor` will be used for the creation of `R`. + /// If a [`Default`] constructor is desired, use [`World::register_required_components`] instead. + /// + /// For the panicking version, see [`World::register_required_components_with`]. + /// + /// Note that requirements must currently be registered before `T` is inserted into the world + /// for the first time. This limitation may be fixed in the future. + /// + /// [required component]: Component#required-components + /// + /// # Errors + /// + /// Returns a [`RequiredComponentsError`] if `R` is already a directly required component for `T`, or if `T` has ever been added + /// on an entity before the registration. + /// + /// Indirect requirements through other components are allowed. In those cases, any existing requirements + /// will only be overwritten if the new requirement is more specific. + /// + /// # Example + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// #[derive(Component)] + /// struct A; + /// + /// #[derive(Component, Default, PartialEq, Eq, Debug)] + /// struct B(usize); + /// + /// #[derive(Component, PartialEq, Eq, Debug)] + /// struct C(u32); + /// + /// # let mut world = World::default(); + /// // Register B and C as required by A and C as required by B. + /// // A requiring C directly will overwrite the indirect requirement through B. + /// world.register_required_components::(); + /// world.register_required_components_with::(|| C(1)); + /// world.register_required_components_with::(|| C(2)); + /// + /// // Duplicate registration! Even if the constructors were different, this would fail. + /// assert!(world.try_register_required_components_with::(|| C(1)).is_err()); + /// + /// // This will implicitly also insert B with its Default constructor and C + /// // with the custom constructor defined by A. + /// let id = world.spawn(A).id(); + /// assert_eq!(&B(0), world.entity(id).get::().unwrap()); + /// assert_eq!(&C(2), world.entity(id).get::().unwrap()); + /// ``` + pub fn try_register_required_components_with( + &mut self, + constructor: fn() -> R, + ) -> Result<(), RequiredComponentsError> { + let requiree = self.register_component::(); + + // TODO: Remove this panic and update archetype edges accordingly when required components are added + if self.archetypes().component_index().contains_key(&requiree) { + return Err(RequiredComponentsError::ArchetypeExists(requiree)); + } + + let required = self.register_component::(); + + // SAFETY: We just created the `required` and `requiree` components. + unsafe { + self.components + .register_required_components::(required, requiree, constructor) + } + } + + /// Retrieves the [required components](RequiredComponents) for the given component type, if it exists. + pub fn get_required_components(&self) -> Option<&RequiredComponents> { + let id = self.components().component_id::()?; + let component_info = self.components().get_info(id)?; + Some(component_info.required_components()) + } + + /// Retrieves the [required components](RequiredComponents) for the component of the given [`ComponentId`], if it exists. + pub fn get_required_components_by_id(&self, id: ComponentId) -> Option<&RequiredComponents> { + let component_info = self.components().get_info(id)?; + Some(component_info.required_components()) + } + /// Registers a new [`Component`] type and returns the [`ComponentId`] created for it. /// /// This method differs from [`World::register_component`] in that it uses a [`ComponentDescriptor`]