Extract required components related items from components

This commit is contained in:
Giacomo Stevanato 2025-07-09 18:09:50 +02:00
parent 6092cb2158
commit dc2befe9af
No known key found for this signature in database
2 changed files with 542 additions and 529 deletions

View File

@ -2,31 +2,27 @@
mod clone;
mod queued_registration;
mod required;
mod tick;
pub use clone::*;
pub use queued_registration::*;
pub use required::*;
pub use tick::*;
use crate::{
archetype::ArchetypeFlags,
bundle::BundleInfo,
change_detection::MaybeLocation,
entity::{Entity, EntityMapper},
entity::EntityMapper,
lifecycle::{ComponentHook, ComponentHooks},
query::DebugCheckedUnwrap,
resource::Resource,
storage::{SparseSetIndex, SparseSets, Table, TableRow},
storage::SparseSetIndex,
system::{Local, SystemParam},
world::{FromWorld, World},
};
use alloc::{borrow::Cow, format, vec::Vec};
use alloc::{borrow::Cow, vec::Vec};
pub use bevy_ecs_macros::Component;
use bevy_platform::sync::Arc;
use bevy_platform::{
collections::{HashMap, HashSet},
sync::PoisonError,
};
use bevy_platform::{collections::HashSet, sync::PoisonError};
use bevy_ptr::OwningPtr;
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::Reflect;
@ -39,8 +35,6 @@ use core::{
mem::needs_drop,
ops::{Deref, DerefMut},
};
use smallvec::SmallVec;
use thiserror::Error;
/// A data type that can be used to store data for an [entity].
///
@ -1304,48 +1298,6 @@ impl<'w> ComponentsRegistrator<'w> {
id
}
// 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` and [required components] inherited from it as required by `T`,
/// and adds `T` to their lists of requirees.
///
/// 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.
///
/// The `recursion_check_stack` allows checking whether this component tried to register itself as its
/// own (indirect) required component.
///
/// This method does *not* register any components as required by 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<T: Component, R: Component>(
&mut self,
required_components: &mut RequiredComponents,
constructor: fn() -> R,
inheritance_depth: u16,
recursion_check_stack: &mut Vec<ComponentId>,
) {
let requiree = self.register_component_checked::<T>(recursion_check_stack);
let required = self.register_component_checked::<R>(recursion_check_stack);
// SAFETY: We just created the components.
unsafe {
self.register_required_components_manual_unchecked::<R>(
requiree,
required,
required_components,
constructor,
inheritance_depth,
);
}
}
/// Registers a [`Resource`] of type `T` with this instance.
/// If a resource of this type has already been registered, this will return
/// the ID of the pre-existing resource.
@ -1613,210 +1565,6 @@ impl Components {
.and_then(|info| info.as_mut().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<R: Component>(
&mut self,
requiree: ComponentId,
required: 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);
let mut required_components_tmp = RequiredComponents::default();
// SAFETY: The caller ensures that the `requiree` and `required` components are valid.
let inherited_requirements = unsafe {
self.register_inherited_required_components(
requiree,
required,
&mut required_components_tmp,
)
};
// SAFETY: The caller ensures that the `requiree` is valid.
let required_components = unsafe {
self.get_required_components_mut(requiree)
.debug_checked_unwrap()
};
required_components.0.extend(required_components_tmp.0);
// 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)
.map(|set| set.iter().copied().collect::<SmallVec<[ComponentId; 8]>>())
{
// `required` is now required by anything that `requiree` was required by.
self.get_required_by_mut(required)
.unwrap()
.extend(required_by.iter().copied());
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 in the "parent" of the requiree.
// The inheritance depth is 1 deeper than the `requiree` wrt `required_by_id`.
let depth = required_components.0.get(&requiree).expect("requiree is required by required_by_id, so its required_components must include requiree").inheritance_depth;
required_components.register_by_id(required, constructor, depth + 1);
for (component_id, component) in inherited_requirements.iter() {
// Register the required component.
// The inheritance depth of inherited components is whatever the requiree's
// depth is relative to `required_by_id`, plus the inheritance depth of the
// inherited component relative to the requiree, plus 1 to account for the
// requiree in between.
// 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_with(
*component_id,
component.inheritance_depth + depth + 1,
|| component.constructor.clone(),
);
};
}
}
}
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,
required_components: &mut RequiredComponents,
) -> 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() {
// Register the required component for the requiree.
// SAFETY: Component ID and constructor match the ones on the original requiree.
unsafe {
required_components.register_dynamic_with(
*component_id,
component.inheritance_depth,
|| component.constructor.clone(),
);
};
// 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
}
/// Registers the given component `R` and [required components] inherited from it as required by `T`,
/// and adds `T` to their lists of requirees.
///
/// 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* register any components as required by 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<R: Component>(
&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);
self.register_inherited_required_components(requiree, required, required_components);
}
#[inline]
pub(crate) fn get_required_by(&self, id: ComponentId) -> Option<&HashSet<ComponentId>> {
self.components
@ -2071,274 +1819,3 @@ impl<T: Component> FromWorld for InitComponentId<T> {
}
}
}
/// 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.
#[derive(Clone)]
pub struct RequiredComponentConstructor(
pub Arc<dyn Fn(&mut Table, &mut SparseSets, Tick, TableRow, Entity, MaybeLocation)>,
);
impl RequiredComponentConstructor {
/// # Safety
/// This is intended to only be called in the context of [`BundleInfo::write_components`] to initialized required components.
/// Calling it _anywhere else_ should be considered unsafe.
///
/// `table_row` and `entity` must correspond to a valid entity that currently needs a component initialized via the constructor stored
/// on this [`RequiredComponentConstructor`]. The stored constructor must correspond to a component on `entity` that needs initialization.
/// `table` and `sparse_sets` must correspond to storages on a world where `entity` needs this required component initialized.
///
/// Again, don't call this anywhere but [`BundleInfo::write_components`].
pub(crate) unsafe fn initialize(
&self,
table: &mut Table,
sparse_sets: &mut SparseSets,
change_tick: Tick,
table_row: TableRow,
entity: Entity,
caller: MaybeLocation,
) {
(self.0)(table, sparse_sets, change_tick, table_row, entity, caller);
}
}
/// 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<ComponentId, RequiredComponent>);
impl Debug for RequiredComponents {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("RequiredComponents")
.field(&self.0.keys())
.finish()
}
}
impl RequiredComponents {
/// 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
///
/// `component_id` must match the type initialized by `constructor`.
/// `constructor` _must_ initialize a component for `component_id` in such a way that
/// matches the storage type of the component. It must only use the given `table_row` or `Entity` to
/// initialize the storage for `component_id` corresponding to the given entity.
pub unsafe fn register_dynamic_with(
&mut self,
component_id: ComponentId,
inheritance_depth: u16,
constructor: impl FnOnce() -> RequiredComponentConstructor,
) {
let entry = self.0.entry(component_id);
match entry {
bevy_platform::collections::hash_map::Entry::Occupied(mut occupied) => {
let current = occupied.get_mut();
if current.inheritance_depth > inheritance_depth {
*current = RequiredComponent {
constructor: constructor(),
inheritance_depth,
}
}
}
bevy_platform::collections::hash_map::Entry::Vacant(vacant) => {
vacant.insert(RequiredComponent {
constructor: constructor(),
inheritance_depth,
});
}
}
}
/// 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<C: Component>(
&mut self,
components: &mut ComponentsRegistrator,
constructor: fn() -> C,
inheritance_depth: u16,
) {
let component_id = components.register_component::<C>();
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<C: Component>(
&mut self,
component_id: ComponentId,
constructor: fn() -> C,
inheritance_depth: u16,
) {
let erased = || {
RequiredComponentConstructor({
// `portable-atomic-util` `Arc` is not able to coerce an unsized
// type like `std::sync::Arc` can. Creating a `Box` first does the
// coercion.
//
// This would be resolved by https://github.com/rust-lang/rust/issues/123430
#[cfg(not(target_has_atomic = "ptr"))]
use alloc::boxed::Box;
type Constructor = dyn for<'a, 'b> Fn(
&'a mut Table,
&'b mut SparseSets,
Tick,
TableRow,
Entity,
MaybeLocation,
);
#[cfg(not(target_has_atomic = "ptr"))]
type Intermediate<T> = Box<T>;
#[cfg(target_has_atomic = "ptr")]
type Intermediate<T> = Arc<T>;
let boxed: Intermediate<Constructor> = Intermediate::new(
move |table, sparse_sets, change_tick, table_row, entity, caller| {
OwningPtr::make(constructor(), |ptr| {
// SAFETY: This will only be called in the context of `BundleInfo::write_components`, which will
// pass in a valid table_row and entity requiring a C constructor
// C::STORAGE_TYPE is the storage type associated with `component_id` / `C`
// `ptr` points to valid `C` data, which matches the type associated with `component_id`
unsafe {
BundleInfo::initialize_required_component(
table,
sparse_sets,
change_tick,
table_row,
entity,
component_id,
C::STORAGE_TYPE,
ptr,
caller,
);
}
});
},
);
Arc::from(boxed)
})
};
// SAFETY:
// `component_id` matches the type initialized by the `erased` constructor above.
// `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_with(component_id, inheritance_depth, erased) };
}
/// Iterates the ids of all required components. This includes recursive required components.
pub fn iter_ids(&self) -> impl Iterator<Item = ComponentId> + '_ {
self.0.keys().copied()
}
/// Removes components that are explicitly provided in a given [`Bundle`]. These components should
/// be logically treated as normal components, not "required components".
///
/// [`Bundle`]: crate::bundle::Bundle
pub(crate) fn remove_explicit_components(&mut self, components: &[ComponentId]) {
for component in components {
self.0.remove(component);
}
}
/// Merges `required_components` into this collection. This only inserts a required component
/// if it _did not already exist_ *or* if the required component is more specific than the existing one
/// (in other words, if the inheritance depth is smaller).
///
/// See [`register_dynamic_with`](Self::register_dynamic_with) for details.
pub(crate) fn merge(&mut self, required_components: &RequiredComponents) {
for (
component_id,
RequiredComponent {
constructor,
inheritance_depth,
},
) in required_components.0.iter()
{
// SAFETY: This exact registration must have been done on `required_components`, so safety is ensured by that caller.
unsafe {
self.register_dynamic_with(*component_id, *inheritance_depth, || {
constructor.clone()
});
}
}
}
}
// NOTE: This should maybe be private, but it is currently public so that `bevy_ecs_macros` can use it.
// This exists as a standalone function instead of being inlined into the component derive macro so as
// to reduce the amount of generated code.
#[doc(hidden)]
pub fn enforce_no_required_components_recursion(
components: &Components,
recursion_check_stack: &[ComponentId],
) {
if let Some((&requiree, check)) = recursion_check_stack.split_last() {
if let Some(direct_recursion) = check
.iter()
.position(|&id| id == requiree)
.map(|index| index == check.len() - 1)
{
panic!(
"Recursive required components detected: {}\nhelp: {}",
recursion_check_stack
.iter()
.map(|id| format!("{}", components.get_name(*id).unwrap().shortname()))
.collect::<Vec<_>>()
.join(""),
if direct_recursion {
format!(
"Remove require({}).",
components.get_name(requiree).unwrap().shortname()
)
} else {
"If this is intentional, consider merging the components.".into()
}
);
}
}
}

View File

@ -0,0 +1,536 @@
use alloc::{format, vec::Vec};
use bevy_platform::{collections::HashMap, sync::Arc};
use bevy_ptr::OwningPtr;
use core::fmt::Debug;
use smallvec::SmallVec;
use thiserror::Error;
use crate::{
bundle::BundleInfo,
change_detection::MaybeLocation,
component::{Component, ComponentId, Components, ComponentsRegistrator, Tick},
entity::Entity,
query::DebugCheckedUnwrap as _,
storage::{SparseSets, Table, TableRow},
};
impl 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<R: Component>(
&mut self,
requiree: ComponentId,
required: 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);
let mut required_components_tmp = RequiredComponents::default();
// SAFETY: The caller ensures that the `requiree` and `required` components are valid.
let inherited_requirements = unsafe {
self.register_inherited_required_components(
requiree,
required,
&mut required_components_tmp,
)
};
// SAFETY: The caller ensures that the `requiree` is valid.
let required_components = unsafe {
self.get_required_components_mut(requiree)
.debug_checked_unwrap()
};
required_components.0.extend(required_components_tmp.0);
// 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)
.map(|set| set.iter().copied().collect::<SmallVec<[ComponentId; 8]>>())
{
// `required` is now required by anything that `requiree` was required by.
self.get_required_by_mut(required)
.unwrap()
.extend(required_by.iter().copied());
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 in the "parent" of the requiree.
// The inheritance depth is 1 deeper than the `requiree` wrt `required_by_id`.
let depth = required_components.0.get(&requiree).expect("requiree is required by required_by_id, so its required_components must include requiree").inheritance_depth;
required_components.register_by_id(required, constructor, depth + 1);
for (component_id, component) in inherited_requirements.iter() {
// Register the required component.
// The inheritance depth of inherited components is whatever the requiree's
// depth is relative to `required_by_id`, plus the inheritance depth of the
// inherited component relative to the requiree, plus 1 to account for the
// requiree in between.
// 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_with(
*component_id,
component.inheritance_depth + depth + 1,
|| component.constructor.clone(),
);
};
}
}
}
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,
required_components: &mut RequiredComponents,
) -> 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() {
// Register the required component for the requiree.
// SAFETY: Component ID and constructor match the ones on the original requiree.
unsafe {
required_components.register_dynamic_with(
*component_id,
component.inheritance_depth,
|| component.constructor.clone(),
);
};
// 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
}
/// Registers the given component `R` and [required components] inherited from it as required by `T`,
/// and adds `T` to their lists of requirees.
///
/// 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* register any components as required by 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<R: Component>(
&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);
self.register_inherited_required_components(requiree, required, required_components);
}
}
impl<'w> ComponentsRegistrator<'w> {
// 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` and [required components] inherited from it as required by `T`,
/// and adds `T` to their lists of requirees.
///
/// 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.
///
/// The `recursion_check_stack` allows checking whether this component tried to register itself as its
/// own (indirect) required component.
///
/// This method does *not* register any components as required by 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<T: Component, R: Component>(
&mut self,
required_components: &mut RequiredComponents,
constructor: fn() -> R,
inheritance_depth: u16,
recursion_check_stack: &mut Vec<ComponentId>,
) {
let requiree = self.register_component_checked::<T>(recursion_check_stack);
let required = self.register_component_checked::<R>(recursion_check_stack);
// SAFETY: We just created the components.
unsafe {
self.register_required_components_manual_unchecked::<R>(
requiree,
required,
required_components,
constructor,
inheritance_depth,
);
}
}
}
/// 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.
#[derive(Clone)]
pub struct RequiredComponentConstructor(
pub Arc<dyn Fn(&mut Table, &mut SparseSets, Tick, TableRow, Entity, MaybeLocation)>,
);
impl RequiredComponentConstructor {
/// # Safety
/// This is intended to only be called in the context of [`BundleInfo::write_components`] to initialized required components.
/// Calling it _anywhere else_ should be considered unsafe.
///
/// `table_row` and `entity` must correspond to a valid entity that currently needs a component initialized via the constructor stored
/// on this [`RequiredComponentConstructor`]. The stored constructor must correspond to a component on `entity` that needs initialization.
/// `table` and `sparse_sets` must correspond to storages on a world where `entity` needs this required component initialized.
///
/// Again, don't call this anywhere but [`BundleInfo::write_components`].
pub(crate) unsafe fn initialize(
&self,
table: &mut Table,
sparse_sets: &mut SparseSets,
change_tick: Tick,
table_row: TableRow,
entity: Entity,
caller: MaybeLocation,
) {
(self.0)(table, sparse_sets, change_tick, table_row, entity, caller);
}
}
/// 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<ComponentId, RequiredComponent>);
impl Debug for RequiredComponents {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("RequiredComponents")
.field(&self.0.keys())
.finish()
}
}
impl RequiredComponents {
/// 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
///
/// `component_id` must match the type initialized by `constructor`.
/// `constructor` _must_ initialize a component for `component_id` in such a way that
/// matches the storage type of the component. It must only use the given `table_row` or `Entity` to
/// initialize the storage for `component_id` corresponding to the given entity.
pub unsafe fn register_dynamic_with(
&mut self,
component_id: ComponentId,
inheritance_depth: u16,
constructor: impl FnOnce() -> RequiredComponentConstructor,
) {
let entry = self.0.entry(component_id);
match entry {
bevy_platform::collections::hash_map::Entry::Occupied(mut occupied) => {
let current = occupied.get_mut();
if current.inheritance_depth > inheritance_depth {
*current = RequiredComponent {
constructor: constructor(),
inheritance_depth,
}
}
}
bevy_platform::collections::hash_map::Entry::Vacant(vacant) => {
vacant.insert(RequiredComponent {
constructor: constructor(),
inheritance_depth,
});
}
}
}
/// 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<C: Component>(
&mut self,
components: &mut ComponentsRegistrator,
constructor: fn() -> C,
inheritance_depth: u16,
) {
let component_id = components.register_component::<C>();
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<C: Component>(
&mut self,
component_id: ComponentId,
constructor: fn() -> C,
inheritance_depth: u16,
) {
let erased = || {
RequiredComponentConstructor({
// `portable-atomic-util` `Arc` is not able to coerce an unsized
// type like `std::sync::Arc` can. Creating a `Box` first does the
// coercion.
//
// This would be resolved by https://github.com/rust-lang/rust/issues/123430
#[cfg(not(target_has_atomic = "ptr"))]
use alloc::boxed::Box;
type Constructor = dyn for<'a, 'b> Fn(
&'a mut Table,
&'b mut SparseSets,
Tick,
TableRow,
Entity,
MaybeLocation,
);
#[cfg(not(target_has_atomic = "ptr"))]
type Intermediate<T> = Box<T>;
#[cfg(target_has_atomic = "ptr")]
type Intermediate<T> = Arc<T>;
let boxed: Intermediate<Constructor> = Intermediate::new(
move |table, sparse_sets, change_tick, table_row, entity, caller| {
OwningPtr::make(constructor(), |ptr| {
// SAFETY: This will only be called in the context of `BundleInfo::write_components`, which will
// pass in a valid table_row and entity requiring a C constructor
// C::STORAGE_TYPE is the storage type associated with `component_id` / `C`
// `ptr` points to valid `C` data, which matches the type associated with `component_id`
unsafe {
BundleInfo::initialize_required_component(
table,
sparse_sets,
change_tick,
table_row,
entity,
component_id,
C::STORAGE_TYPE,
ptr,
caller,
);
}
});
},
);
Arc::from(boxed)
})
};
// SAFETY:
// `component_id` matches the type initialized by the `erased` constructor above.
// `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_with(component_id, inheritance_depth, erased) };
}
/// Iterates the ids of all required components. This includes recursive required components.
pub fn iter_ids(&self) -> impl Iterator<Item = ComponentId> + '_ {
self.0.keys().copied()
}
/// Removes components that are explicitly provided in a given [`Bundle`]. These components should
/// be logically treated as normal components, not "required components".
///
/// [`Bundle`]: crate::bundle::Bundle
pub(crate) fn remove_explicit_components(&mut self, components: &[ComponentId]) {
for component in components {
self.0.remove(component);
}
}
/// Merges `required_components` into this collection. This only inserts a required component
/// if it _did not already exist_ *or* if the required component is more specific than the existing one
/// (in other words, if the inheritance depth is smaller).
///
/// See [`register_dynamic_with`](Self::register_dynamic_with) for details.
pub(crate) fn merge(&mut self, required_components: &RequiredComponents) {
for (
component_id,
RequiredComponent {
constructor,
inheritance_depth,
},
) in required_components.0.iter()
{
// SAFETY: This exact registration must have been done on `required_components`, so safety is ensured by that caller.
unsafe {
self.register_dynamic_with(*component_id, *inheritance_depth, || {
constructor.clone()
});
}
}
}
}
// NOTE: This should maybe be private, but it is currently public so that `bevy_ecs_macros` can use it.
// This exists as a standalone function instead of being inlined into the component derive macro so as
// to reduce the amount of generated code.
#[doc(hidden)]
pub fn enforce_no_required_components_recursion(
components: &Components,
recursion_check_stack: &[ComponentId],
) {
if let Some((&requiree, check)) = recursion_check_stack.split_last() {
if let Some(direct_recursion) = check
.iter()
.position(|&id| id == requiree)
.map(|index| index == check.len() - 1)
{
panic!(
"Recursive required components detected: {}\nhelp: {}",
recursion_check_stack
.iter()
.map(|id| format!("{}", components.get_name(*id).unwrap().shortname()))
.collect::<Vec<_>>()
.join(""),
if direct_recursion {
format!(
"Remove require({}).",
components.get_name(requiree).unwrap().shortname()
)
} else {
"If this is intentional, consider merging the components.".into()
}
);
}
}
}