diff --git a/crates/bevy_core_widgets/src/core_slider.rs b/crates/bevy_core_widgets/src/core_slider.rs index 521e6fc1d3..07efc7e800 100644 --- a/crates/bevy_core_widgets/src/core_slider.rs +++ b/crates/bevy_core_widgets/src/core_slider.rs @@ -19,6 +19,7 @@ use bevy_input::keyboard::{KeyCode, KeyboardInput}; use bevy_input::ButtonState; use bevy_input_focus::FocusedInput; use bevy_log::warn_once; +use bevy_math::ops; use bevy_picking::events::{Drag, DragEnd, DragStart, Pointer, Press}; use bevy_ui::{ComputedNode, ComputedNodeTarget, InteractionDisabled, UiGlobalTransform, UiScale}; @@ -38,7 +39,8 @@ pub enum TrackClick { /// A headless slider widget, which can be used to build custom sliders. Sliders have a value /// (represented by the [`SliderValue`] component) and a range (represented by [`SliderRange`]). An -/// optional step size can be specified via [`SliderStep`]. +/// optional step size can be specified via [`SliderStep`], and you can control the rounding +/// during dragging with [`SliderPrecision`]. /// /// You can also control the slider remotely by triggering a [`SetSliderValue`] event on it. This /// can be useful in a console environment for controlling the value gamepad inputs. @@ -187,6 +189,25 @@ impl Default for SliderStep { } } +/// A component which controls the rounding of the slider value during dragging. +/// +/// Stepping is not affected, although presumably the step size will be an integer multiple of the +/// rounding factor. This also doesn't prevent the slider value from being set to non-rounded values +/// by other means, such as manually entering digits via a numeric input field. +/// +/// The value in this component represents the number of decimal places of desired precision, so a +/// value of 2 would round to the nearest 1/100th. A value of -3 would round to the nearest +/// thousand. +#[derive(Component, Debug, Default, Clone, Copy)] +pub struct SliderPrecision(pub i32); + +impl SliderPrecision { + fn round(&self, value: f32) -> f32 { + let factor = ops::powf(10.0_f32, self.0 as f32); + (value * factor).round() / factor + } +} + /// Component used to manage the state of a slider during dragging. #[derive(Component, Default)] pub struct CoreSliderDragState { @@ -204,6 +225,7 @@ pub(crate) fn slider_on_pointer_down( &SliderValue, &SliderRange, &SliderStep, + Option<&SliderPrecision>, &ComputedNode, &ComputedNodeTarget, &UiGlobalTransform, @@ -217,8 +239,17 @@ pub(crate) fn slider_on_pointer_down( if q_thumb.contains(trigger.target()) { // Thumb click, stop propagation to prevent track click. trigger.propagate(false); - } else if let Ok((slider, value, range, step, node, node_target, transform, disabled)) = - q_slider.get(trigger.target()) + } else if let Ok(( + slider, + value, + range, + step, + precision, + node, + node_target, + transform, + disabled, + )) = q_slider.get(trigger.target()) { // Track click trigger.propagate(false); @@ -257,7 +288,9 @@ pub(crate) fn slider_on_pointer_down( value.0 + step.0 } } - TrackClick::Snap => click_val, + TrackClick::Snap => precision + .map(|prec| prec.round(click_val)) + .unwrap_or(click_val), }); if matches!(slider.on_change, Callback::Ignore) { @@ -296,6 +329,7 @@ pub(crate) fn slider_on_drag( &ComputedNode, &CoreSlider, &SliderRange, + Option<&SliderPrecision>, &UiGlobalTransform, &mut CoreSliderDragState, Has, @@ -305,7 +339,8 @@ pub(crate) fn slider_on_drag( mut commands: Commands, ui_scale: Res, ) { - if let Ok((node, slider, range, transform, drag, disabled)) = q_slider.get_mut(trigger.target()) + if let Ok((node, slider, range, precision, transform, drag, disabled)) = + q_slider.get_mut(trigger.target()) { trigger.propagate(false); if drag.dragging && !disabled { @@ -320,17 +355,22 @@ pub(crate) fn slider_on_drag( let slider_width = ((node.size().x - thumb_size) * node.inverse_scale_factor).max(1.0); let span = range.span(); let new_value = if span > 0. { - range.clamp(drag.offset + (distance.x * span) / slider_width) + drag.offset + (distance.x * span) / slider_width } else { range.start() + span * 0.5 }; + let rounded_value = range.clamp( + precision + .map(|prec| prec.round(new_value)) + .unwrap_or(new_value), + ); if matches!(slider.on_change, Callback::Ignore) { commands .entity(trigger.target()) - .insert(SliderValue(new_value)); + .insert(SliderValue(rounded_value)); } else { - commands.notify_with(&slider.on_change, new_value); + commands.notify_with(&slider.on_change, rounded_value); } } } @@ -491,3 +531,24 @@ impl Plugin for CoreSliderPlugin { .add_observer(slider_on_set_value); } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_slider_precision_rounding() { + // Test positive precision values (decimal places) + let precision_2dp = SliderPrecision(2); + assert_eq!(precision_2dp.round(1.234567), 1.23); + assert_eq!(precision_2dp.round(1.235), 1.24); + + // Test zero precision (rounds to integers) + let precision_0dp = SliderPrecision(0); + assert_eq!(precision_0dp.round(1.4), 1.0); + + // Test negative precision (rounds to tens, hundreds, etc.) + let precision_neg1 = SliderPrecision(-1); + assert_eq!(precision_neg1.round(14.0), 10.0); + } +} diff --git a/crates/bevy_core_widgets/src/lib.rs b/crates/bevy_core_widgets/src/lib.rs index 3fc13c5c0e..eb05a18ba6 100644 --- a/crates/bevy_core_widgets/src/lib.rs +++ b/crates/bevy_core_widgets/src/lib.rs @@ -33,7 +33,7 @@ pub use core_scrollbar::{ }; pub use core_slider::{ CoreSlider, CoreSliderDragState, CoreSliderPlugin, CoreSliderThumb, SetSliderValue, - SliderRange, SliderStep, SliderValue, TrackClick, + SliderPrecision, SliderRange, SliderStep, SliderValue, TrackClick, }; /// A plugin group that registers the observers for all of the core widgets. If you don't want to diff --git a/crates/bevy_ecs/src/component.rs b/crates/bevy_ecs/src/component.rs deleted file mode 100644 index 615c5903f8..0000000000 --- a/crates/bevy_ecs/src/component.rs +++ /dev/null @@ -1,3049 +0,0 @@ -//! Types for declaring and storing [`Component`]s. - -use crate::{ - archetype::ArchetypeFlags, - bundle::BundleInfo, - change_detection::{MaybeLocation, MAX_CHANGE_AGE}, - entity::{ComponentCloneCtx, Entity, EntityMapper, SourceComponent}, - lifecycle::{ComponentHook, ComponentHooks}, - query::DebugCheckedUnwrap, - resource::Resource, - storage::{SparseSetIndex, SparseSets, Table, TableRow}, - system::{Local, SystemParam}, - world::{FromWorld, World}, -}; -use alloc::boxed::Box; -use alloc::{borrow::Cow, format, vec::Vec}; -pub use bevy_ecs_macros::Component; -use bevy_ecs_macros::Event; -use bevy_platform::sync::Arc; -use bevy_platform::{ - collections::{HashMap, HashSet}, - sync::PoisonError, -}; -use bevy_ptr::{OwningPtr, UnsafeCellDeref}; -#[cfg(feature = "bevy_reflect")] -use bevy_reflect::Reflect; -use bevy_utils::{prelude::DebugName, TypeIdMap}; -use core::{ - alloc::Layout, - any::{Any, TypeId}, - cell::UnsafeCell, - fmt::Debug, - marker::PhantomData, - 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]. -/// -/// `Component` is a [derivable trait]: this means that a data type can implement it by applying a `#[derive(Component)]` attribute to it. -/// However, components must always satisfy the `Send + Sync + 'static` trait bounds. -/// -/// [entity]: crate::entity -/// [derivable trait]: https://doc.rust-lang.org/book/appendix-03-derivable-traits.html -/// -/// # Examples -/// -/// Components can take many forms: they are usually structs, but can also be of every other kind of data type, like enums or zero sized types. -/// The following examples show how components are laid out in code. -/// -/// ``` -/// # use bevy_ecs::component::Component; -/// # struct Color; -/// # -/// // A component can contain data... -/// #[derive(Component)] -/// struct LicensePlate(String); -/// -/// // ... but it can also be a zero-sized marker. -/// #[derive(Component)] -/// struct Car; -/// -/// // Components can also be structs with named fields... -/// #[derive(Component)] -/// struct VehiclePerformance { -/// acceleration: f32, -/// top_speed: f32, -/// handling: f32, -/// } -/// -/// // ... or enums. -/// #[derive(Component)] -/// enum WheelCount { -/// Two, -/// Three, -/// Four, -/// } -/// ``` -/// -/// # Component and data access -/// -/// Components can be marked as immutable by adding the `#[component(immutable)]` -/// attribute when using the derive macro. -/// See the documentation for [`ComponentMutability`] for more details around this -/// feature. -/// -/// See the [`entity`] module level documentation to learn how to add or remove components from an entity. -/// -/// See the documentation for [`Query`] to learn how to access component data from a system. -/// -/// [`entity`]: crate::entity#usage -/// [`Query`]: crate::system::Query -/// [`ComponentMutability`]: crate::component::ComponentMutability -/// -/// # Choosing a storage type -/// -/// Components can be stored in the world using different strategies with their own performance implications. -/// By default, components are added to the [`Table`] storage, which is optimized for query iteration. -/// -/// Alternatively, components can be added to the [`SparseSet`] storage, which is optimized for component insertion and removal. -/// This is achieved by adding an additional `#[component(storage = "SparseSet")]` attribute to the derive one: -/// -/// ``` -/// # use bevy_ecs::component::Component; -/// # -/// #[derive(Component)] -/// #[component(storage = "SparseSet")] -/// struct ComponentA; -/// ``` -/// -/// [`Table`]: crate::storage::Table -/// [`SparseSet`]: crate::storage::SparseSet -/// -/// # Required Components -/// -/// Components can specify Required Components. If some [`Component`] `A` requires [`Component`] `B`, then when `A` is inserted, -/// `B` will _also_ be initialized and inserted (if it was not manually specified). -/// -/// The [`Default`] constructor will be used to initialize the component, by default: -/// -/// ``` -/// # use bevy_ecs::prelude::*; -/// #[derive(Component)] -/// #[require(B)] -/// struct A; -/// -/// #[derive(Component, Default, PartialEq, Eq, Debug)] -/// struct B(usize); -/// -/// # let mut world = World::default(); -/// // This will implicitly also insert B with the Default constructor -/// let id = world.spawn(A).id(); -/// assert_eq!(&B(0), world.entity(id).get::().unwrap()); -/// -/// // This will _not_ implicitly insert B, because it was already provided -/// world.spawn((A, B(11))); -/// ``` -/// -/// Components can have more than one required component: -/// -/// ``` -/// # use bevy_ecs::prelude::*; -/// #[derive(Component)] -/// #[require(B, C)] -/// struct A; -/// -/// #[derive(Component, Default, PartialEq, Eq, Debug)] -/// #[require(C)] -/// struct B(usize); -/// -/// #[derive(Component, Default, PartialEq, Eq, Debug)] -/// struct C(u32); -/// -/// # let mut world = World::default(); -/// // 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()); -/// ``` -/// -/// You can define inline component values that take the following forms: -/// ``` -/// # use bevy_ecs::prelude::*; -/// #[derive(Component)] -/// #[require( -/// B(1), // tuple structs -/// C { // named-field structs -/// x: 1, -/// ..Default::default() -/// }, -/// D::One, // enum variants -/// E::ONE, // associated consts -/// F::new(1) // constructors -/// )] -/// struct A; -/// -/// #[derive(Component, PartialEq, Eq, Debug)] -/// struct B(u8); -/// -/// #[derive(Component, PartialEq, Eq, Debug, Default)] -/// struct C { -/// x: u8, -/// y: u8, -/// } -/// -/// #[derive(Component, PartialEq, Eq, Debug)] -/// enum D { -/// Zero, -/// One, -/// } -/// -/// #[derive(Component, PartialEq, Eq, Debug)] -/// struct E(u8); -/// -/// impl E { -/// pub const ONE: Self = Self(1); -/// } -/// -/// #[derive(Component, PartialEq, Eq, Debug)] -/// struct F(u8); -/// -/// impl F { -/// fn new(value: u8) -> Self { -/// Self(value) -/// } -/// } -/// -/// # let mut world = World::default(); -/// let id = world.spawn(A).id(); -/// assert_eq!(&B(1), world.entity(id).get::().unwrap()); -/// assert_eq!(&C { x: 1, y: 0 }, world.entity(id).get::().unwrap()); -/// assert_eq!(&D::One, world.entity(id).get::().unwrap()); -/// assert_eq!(&E(1), world.entity(id).get::().unwrap()); -/// assert_eq!(&F(1), world.entity(id).get::().unwrap()); -/// ```` -/// -/// -/// You can also define arbitrary expressions by using `=` -/// -/// ``` -/// # use bevy_ecs::prelude::*; -/// #[derive(Component)] -/// #[require(C = init_c())] -/// struct A; -/// -/// #[derive(Component, PartialEq, Eq, Debug)] -/// #[require(C = C(20))] -/// struct B; -/// -/// #[derive(Component, PartialEq, Eq, Debug)] -/// struct C(usize); -/// -/// fn init_c() -> C { -/// C(10) -/// } -/// -/// # let mut world = World::default(); -/// // This will implicitly also insert C with the init_c() constructor -/// let id = world.spawn(A).id(); -/// assert_eq!(&C(10), world.entity(id).get::().unwrap()); -/// -/// // This will implicitly also insert C with the `|| C(20)` constructor closure -/// let id = world.spawn(B).id(); -/// assert_eq!(&C(20), world.entity(id).get::().unwrap()); -/// ``` -/// -/// Required components are _recursive_. This means, if a Required Component has required components, -/// those components will _also_ be inserted if they are missing: -/// -/// ``` -/// # use bevy_ecs::prelude::*; -/// #[derive(Component)] -/// #[require(B)] -/// struct A; -/// -/// #[derive(Component, Default, PartialEq, Eq, Debug)] -/// #[require(C)] -/// struct B(usize); -/// -/// #[derive(Component, Default, PartialEq, Eq, Debug)] -/// struct C(u32); -/// -/// # let mut world = World::default(); -/// // 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()); -/// ``` -/// -/// Note that cycles in the "component require tree" will result in stack overflows when attempting to -/// insert a component. -/// -/// This "multiple inheritance" pattern does mean that it is possible to have duplicate requires for a given type -/// at different levels of the inheritance tree: -/// -/// ``` -/// # use bevy_ecs::prelude::*; -/// #[derive(Component)] -/// struct X(usize); -/// -/// #[derive(Component, Default)] -/// #[require(X(1))] -/// struct Y; -/// -/// #[derive(Component)] -/// #[require( -/// Y, -/// X(2), -/// )] -/// struct Z; -/// -/// # let mut world = World::default(); -/// // In this case, the x2 constructor is used for X -/// let id = world.spawn(Z).id(); -/// assert_eq!(2, world.entity(id).get::().unwrap().0); -/// ``` -/// -/// In general, this shouldn't happen often, but when it does the algorithm for choosing the constructor from the tree is simple and predictable: -/// 1. A constructor from a direct `#[require()]`, if one exists, is selected with priority. -/// 2. Otherwise, perform a Depth First Search on the tree of requirements and select the first one found. -/// -/// From a user perspective, just think about this as the following: -/// 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. -/// -/// # Relationships between Entities -/// -/// Sometimes it is useful to define relationships between entities. A common example is the -/// parent / child relationship. Since Components are how data is stored for Entities, one might -/// naturally think to create a Component which has a field of type [`Entity`]. -/// -/// To facilitate this pattern, Bevy provides the [`Relationship`](`crate::relationship::Relationship`) -/// trait. You can derive the [`Relationship`](`crate::relationship::Relationship`) and -/// [`RelationshipTarget`](`crate::relationship::RelationshipTarget`) traits in addition to the -/// Component trait in order to implement data driven relationships between entities, see the trait -/// docs for more details. -/// -/// In addition, Bevy provides canonical implementations of the parent / child relationship via the -/// [`ChildOf`](crate::hierarchy::ChildOf) [`Relationship`](crate::relationship::Relationship) and -/// the [`Children`](crate::hierarchy::Children) -/// [`RelationshipTarget`](crate::relationship::RelationshipTarget). -/// -/// # Adding component's hooks -/// -/// See [`ComponentHooks`] for a detailed explanation of component's hooks. -/// -/// Alternatively to the example shown in [`ComponentHooks`]' documentation, hooks can be configured using following attributes: -/// - `#[component(on_add = on_add_function)]` -/// - `#[component(on_insert = on_insert_function)]` -/// - `#[component(on_replace = on_replace_function)]` -/// - `#[component(on_remove = on_remove_function)]` -/// -/// ``` -/// # use bevy_ecs::component::Component; -/// # use bevy_ecs::lifecycle::HookContext; -/// # use bevy_ecs::world::DeferredWorld; -/// # use bevy_ecs::entity::Entity; -/// # use bevy_ecs::component::ComponentId; -/// # use core::panic::Location; -/// # -/// #[derive(Component)] -/// #[component(on_add = my_on_add_hook)] -/// #[component(on_insert = my_on_insert_hook)] -/// // Another possible way of configuring hooks: -/// // #[component(on_add = my_on_add_hook, on_insert = my_on_insert_hook)] -/// // -/// // We don't have a replace or remove hook, so we can leave them out: -/// // #[component(on_replace = my_on_replace_hook, on_remove = my_on_remove_hook)] -/// struct ComponentA; -/// -/// fn my_on_add_hook(world: DeferredWorld, context: HookContext) { -/// // ... -/// } -/// -/// // You can also destructure items directly in the signature -/// fn my_on_insert_hook(world: DeferredWorld, HookContext { caller, .. }: HookContext) { -/// // ... -/// } -/// ``` -/// -/// This also supports function calls that yield closures -/// -/// ``` -/// # use bevy_ecs::component::Component; -/// # use bevy_ecs::lifecycle::HookContext; -/// # use bevy_ecs::world::DeferredWorld; -/// # -/// #[derive(Component)] -/// #[component(on_add = my_msg_hook("hello"))] -/// #[component(on_despawn = my_msg_hook("yoink"))] -/// struct ComponentA; -/// -/// // a hook closure generating function -/// fn my_msg_hook(message: &'static str) -> impl Fn(DeferredWorld, HookContext) { -/// move |_world, _ctx| { -/// println!("{message}"); -/// } -/// } -/// -/// ``` -/// # Setting the clone behavior -/// -/// You can specify how the [`Component`] is cloned when deriving it. -/// -/// Your options are the functions and variants of [`ComponentCloneBehavior`] -/// See [Handlers section of `EntityClonerBuilder`](crate::entity::EntityClonerBuilder#handlers) to understand how this affects handler priority. -/// ``` -/// # use bevy_ecs::prelude::*; -/// -/// #[derive(Component)] -/// #[component(clone_behavior = Ignore)] -/// struct MyComponent; -/// -/// ``` -/// -/// # Implementing the trait for foreign types -/// -/// As a consequence of the [orphan rule], it is not possible to separate into two different crates the implementation of `Component` from the definition of a type. -/// This means that it is not possible to directly have a type defined in a third party library as a component. -/// This important limitation can be easily worked around using the [newtype pattern]: -/// this makes it possible to locally define and implement `Component` for a tuple struct that wraps the foreign type. -/// The following example gives a demonstration of this pattern. -/// -/// ``` -/// // `Component` is defined in the `bevy_ecs` crate. -/// use bevy_ecs::component::Component; -/// -/// // `Duration` is defined in the `std` crate. -/// use std::time::Duration; -/// -/// // It is not possible to implement `Component` for `Duration` from this position, as they are -/// // both foreign items, defined in an external crate. However, nothing prevents to define a new -/// // `Cooldown` type that wraps `Duration`. As `Cooldown` is defined in a local crate, it is -/// // possible to implement `Component` for it. -/// #[derive(Component)] -/// struct Cooldown(Duration); -/// ``` -/// -/// [orphan rule]: https://doc.rust-lang.org/book/ch10-02-traits.html#implementing-a-trait-on-a-type -/// [newtype pattern]: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#using-the-newtype-pattern-to-implement-external-traits-on-external-types -/// -/// # `!Sync` Components -/// A `!Sync` type cannot implement `Component`. However, it is possible to wrap a `Send` but not `Sync` -/// type in [`SyncCell`] or the currently unstable [`Exclusive`] to make it `Sync`. This forces only -/// having mutable access (`&mut T` only, never `&T`), but makes it safe to reference across multiple -/// threads. -/// -/// This will fail to compile since `RefCell` is `!Sync`. -/// ```compile_fail -/// # use std::cell::RefCell; -/// # use bevy_ecs::component::Component; -/// #[derive(Component)] -/// struct NotSync { -/// counter: RefCell, -/// } -/// ``` -/// -/// This will compile since the `RefCell` is wrapped with `SyncCell`. -/// ``` -/// # use std::cell::RefCell; -/// # use bevy_ecs::component::Component; -/// use bevy_platform::cell::SyncCell; -/// -/// // This will compile. -/// #[derive(Component)] -/// struct ActuallySync { -/// counter: SyncCell>, -/// } -/// ``` -/// -/// [`SyncCell`]: bevy_platform::cell::SyncCell -/// [`Exclusive`]: https://doc.rust-lang.org/nightly/std/sync/struct.Exclusive.html -#[diagnostic::on_unimplemented( - message = "`{Self}` is not a `Component`", - label = "invalid `Component`", - note = "consider annotating `{Self}` with `#[derive(Component)]`" -)] -pub trait Component: Send + Sync + 'static { - /// A constant indicating the storage type used for this component. - const STORAGE_TYPE: StorageType; - - /// A marker type to assist Bevy with determining if this component is - /// mutable, or immutable. Mutable components will have [`Component`], - /// while immutable components will instead have [`Component`]. - /// - /// * For a component to be mutable, this type must be [`Mutable`]. - /// * For a component to be immutable, this type must be [`Immutable`]. - type Mutability: ComponentMutability; - - /// Gets the `on_add` [`ComponentHook`] for this [`Component`] if one is defined. - fn on_add() -> Option { - None - } - - /// Gets the `on_insert` [`ComponentHook`] for this [`Component`] if one is defined. - fn on_insert() -> Option { - None - } - - /// Gets the `on_replace` [`ComponentHook`] for this [`Component`] if one is defined. - fn on_replace() -> Option { - None - } - - /// Gets the `on_remove` [`ComponentHook`] for this [`Component`] if one is defined. - fn on_remove() -> Option { - None - } - - /// Gets the `on_despawn` [`ComponentHook`] for this [`Component`] if one is defined. - fn on_despawn() -> Option { - None - } - - /// Registers required components. - fn register_required_components( - _component_id: ComponentId, - _components: &mut ComponentsRegistrator, - _required_components: &mut RequiredComponents, - _inheritance_depth: u16, - _recursion_check_stack: &mut Vec, - ) { - } - - /// Called when registering this component, allowing to override clone function (or disable cloning altogether) for this component. - /// - /// See [Handlers section of `EntityClonerBuilder`](crate::entity::EntityClonerBuilder#handlers) to understand how this affects handler priority. - #[inline] - fn clone_behavior() -> ComponentCloneBehavior { - ComponentCloneBehavior::Default - } - - /// Maps the entities on this component using the given [`EntityMapper`]. This is used to remap entities in contexts like scenes and entity cloning. - /// When deriving [`Component`], this is populated by annotating fields containing entities with `#[entities]` - /// - /// ``` - /// # use bevy_ecs::{component::Component, entity::Entity}; - /// #[derive(Component)] - /// struct Inventory { - /// #[entities] - /// items: Vec - /// } - /// ``` - /// - /// Fields with `#[entities]` must implement [`MapEntities`](crate::entity::MapEntities). - /// - /// Bevy provides various implementations of [`MapEntities`](crate::entity::MapEntities), so that arbitrary combinations like these are supported with `#[entities]`: - /// - /// ```rust - /// # use bevy_ecs::{component::Component, entity::Entity}; - /// #[derive(Component)] - /// struct Inventory { - /// #[entities] - /// items: Vec> - /// } - /// ``` - /// - /// You might need more specialized logic. A likely cause of this is your component contains collections of entities that - /// don't implement [`MapEntities`](crate::entity::MapEntities). In that case, you can annotate your component with - /// `#[component(map_entities)]`. Using this attribute, you must implement `MapEntities` for the - /// component itself, and this method will simply call that implementation. - /// - /// ``` - /// # use bevy_ecs::{component::Component, entity::{Entity, MapEntities, EntityMapper}}; - /// # use std::collections::HashMap; - /// #[derive(Component)] - /// #[component(map_entities)] - /// struct Inventory { - /// items: HashMap - /// } - /// - /// impl MapEntities for Inventory { - /// fn map_entities(&mut self, entity_mapper: &mut M) { - /// self.items = self.items - /// .drain() - /// .map(|(id, count)|(entity_mapper.get_mapped(id), count)) - /// .collect(); - /// } - /// } - /// # let a = Entity::from_bits(0x1_0000_0001); - /// # let b = Entity::from_bits(0x1_0000_0002); - /// # let mut inv = Inventory { items: Default::default() }; - /// # inv.items.insert(a, 10); - /// # ::map_entities(&mut inv, &mut (a,b)); - /// # assert_eq!(inv.items.get(&b), Some(&10)); - /// ```` - /// - /// Alternatively, you can specify the path to a function with `#[component(map_entities = function_path)]`, similar to component hooks. - /// In this case, the inputs of the function should mirror the inputs to this method, with the second parameter being generic. - /// - /// ``` - /// # use bevy_ecs::{component::Component, entity::{Entity, MapEntities, EntityMapper}}; - /// # use std::collections::HashMap; - /// #[derive(Component)] - /// #[component(map_entities = map_the_map)] - /// // Also works: map_the_map:: or map_the_map::<_> - /// struct Inventory { - /// items: HashMap - /// } - /// - /// fn map_the_map(inv: &mut Inventory, entity_mapper: &mut M) { - /// inv.items = inv.items - /// .drain() - /// .map(|(id, count)|(entity_mapper.get_mapped(id), count)) - /// .collect(); - /// } - /// # let a = Entity::from_bits(0x1_0000_0001); - /// # let b = Entity::from_bits(0x1_0000_0002); - /// # let mut inv = Inventory { items: Default::default() }; - /// # inv.items.insert(a, 10); - /// # ::map_entities(&mut inv, &mut (a,b)); - /// # assert_eq!(inv.items.get(&b), Some(&10)); - /// ```` - /// - /// You can use the turbofish (`::`) to specify parameters when a function is generic, using either M or _ for the type of the mapper parameter. - #[inline] - fn map_entities(_this: &mut Self, _mapper: &mut E) {} -} - -mod private { - pub trait Seal {} -} - -/// The mutability option for a [`Component`]. This can either be: -/// * [`Mutable`] -/// * [`Immutable`] -/// -/// This is controlled through either [`Component::Mutability`] or `#[component(immutable)]` -/// when using the derive macro. -/// -/// Immutable components are guaranteed to never have an exclusive reference, -/// `&mut ...`, created while inserted onto an entity. -/// In all other ways, they are identical to mutable components. -/// This restriction allows hooks to observe all changes made to an immutable -/// component, effectively turning the `Insert` and `Replace` hooks into a -/// `OnMutate` hook. -/// This is not practical for mutable components, as the runtime cost of invoking -/// a hook for every exclusive reference created would be far too high. -/// -/// # Examples -/// -/// ```rust -/// # use bevy_ecs::component::Component; -/// # -/// #[derive(Component)] -/// #[component(immutable)] -/// struct ImmutableFoo; -/// ``` -pub trait ComponentMutability: private::Seal + 'static { - /// Boolean to indicate if this mutability setting implies a mutable or immutable - /// component. - const MUTABLE: bool; -} - -/// Parameter indicating a [`Component`] is immutable. -/// -/// See [`ComponentMutability`] for details. -pub struct Immutable; - -impl private::Seal for Immutable {} - -impl ComponentMutability for Immutable { - const MUTABLE: bool = false; -} - -/// Parameter indicating a [`Component`] is mutable. -/// -/// See [`ComponentMutability`] for details. -pub struct Mutable; - -impl private::Seal for Mutable {} - -impl ComponentMutability for Mutable { - const MUTABLE: bool = true; -} - -/// The storage used for a specific component type. -/// -/// # Examples -/// The [`StorageType`] for a component is configured via the derive attribute -/// -/// ``` -/// # use bevy_ecs::{prelude::*, component::*}; -/// #[derive(Component)] -/// #[component(storage = "SparseSet")] -/// struct A; -/// ``` -#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)] -pub enum StorageType { - /// Provides fast and cache-friendly iteration, but slower addition and removal of components. - /// This is the default storage type. - #[default] - Table, - /// Provides fast addition and removal of components, but slower iteration. - SparseSet, -} - -/// Stores metadata for a type of component or resource stored in a specific [`World`]. -#[derive(Debug, Clone)] -pub struct ComponentInfo { - id: ComponentId, - descriptor: ComponentDescriptor, - hooks: ComponentHooks, - required_components: RequiredComponents, - required_by: HashSet, -} - -impl ComponentInfo { - /// Returns a value uniquely identifying the current component. - #[inline] - pub fn id(&self) -> ComponentId { - self.id - } - - /// Returns the name of the current component. - #[inline] - pub fn name(&self) -> DebugName { - self.descriptor.name.clone() - } - - /// Returns `true` if the current component is mutable. - #[inline] - pub fn mutable(&self) -> bool { - self.descriptor.mutable - } - - /// Returns [`ComponentCloneBehavior`] of the current component. - #[inline] - pub fn clone_behavior(&self) -> &ComponentCloneBehavior { - &self.descriptor.clone_behavior - } - - /// Returns the [`TypeId`] of the underlying component type. - /// Returns `None` if the component does not correspond to a Rust type. - #[inline] - pub fn type_id(&self) -> Option { - self.descriptor.type_id - } - - /// Returns the layout used to store values of this component in memory. - #[inline] - pub fn layout(&self) -> Layout { - self.descriptor.layout - } - - #[inline] - /// Get the function which should be called to clean up values of - /// the underlying component type. This maps to the - /// [`Drop`] implementation for 'normal' Rust components - /// - /// Returns `None` if values of the underlying component type don't - /// need to be dropped, e.g. as reported by [`needs_drop`]. - pub fn drop(&self) -> Option)> { - self.descriptor.drop - } - - /// Returns a value indicating the storage strategy for the current component. - #[inline] - pub fn storage_type(&self) -> StorageType { - self.descriptor.storage_type - } - - /// Returns `true` if the underlying component type can be freely shared between threads. - /// If this returns `false`, then extra care must be taken to ensure that components - /// are not accessed from the wrong thread. - #[inline] - pub fn is_send_and_sync(&self) -> bool { - self.descriptor.is_send_and_sync - } - - /// Create a new [`ComponentInfo`]. - pub(crate) fn new(id: ComponentId, descriptor: ComponentDescriptor) -> Self { - ComponentInfo { - id, - descriptor, - hooks: Default::default(), - required_components: Default::default(), - required_by: Default::default(), - } - } - - /// Update the given flags to include any [`ComponentHook`] registered to self - #[inline] - pub(crate) fn update_archetype_flags(&self, flags: &mut ArchetypeFlags) { - if self.hooks().on_add.is_some() { - flags.insert(ArchetypeFlags::ON_ADD_HOOK); - } - if self.hooks().on_insert.is_some() { - flags.insert(ArchetypeFlags::ON_INSERT_HOOK); - } - if self.hooks().on_replace.is_some() { - flags.insert(ArchetypeFlags::ON_REPLACE_HOOK); - } - if self.hooks().on_remove.is_some() { - flags.insert(ArchetypeFlags::ON_REMOVE_HOOK); - } - if self.hooks().on_despawn.is_some() { - flags.insert(ArchetypeFlags::ON_DESPAWN_HOOK); - } - } - - /// Provides a reference to the collection of hooks associated with this [`Component`] - pub fn hooks(&self) -> &ComponentHooks { - &self.hooks - } - - /// Retrieves the [`RequiredComponents`] collection, which contains all required components (and their constructors) - /// needed by this component. This includes _recursive_ required components. - pub fn required_components(&self) -> &RequiredComponents { - &self.required_components - } -} - -/// A value which uniquely identifies the type of a [`Component`] or [`Resource`] within a -/// [`World`]. -/// -/// Each time a new `Component` type is registered within a `World` using -/// e.g. [`World::register_component`] or [`World::register_component_with_descriptor`] -/// or a Resource with e.g. [`World::init_resource`], -/// a corresponding `ComponentId` is created to track it. -/// -/// While the distinction between `ComponentId` and [`TypeId`] may seem superficial, breaking them -/// into two separate but related concepts allows components to exist outside of Rust's type system. -/// Each Rust type registered as a `Component` will have a corresponding `ComponentId`, but additional -/// `ComponentId`s may exist in a `World` to track components which cannot be -/// represented as Rust types for scripting or other advanced use-cases. -/// -/// A `ComponentId` is tightly coupled to its parent `World`. Attempting to use a `ComponentId` from -/// one `World` to access the metadata of a `Component` in a different `World` is undefined behavior -/// and must not be attempted. -/// -/// Given a type `T` which implements [`Component`], the `ComponentId` for `T` can be retrieved -/// from a `World` using [`World::component_id()`] or via [`Components::component_id()`]. Access -/// to the `ComponentId` for a [`Resource`] is available via [`Components::resource_id()`]. -#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)] -#[cfg_attr( - feature = "bevy_reflect", - derive(Reflect), - reflect(Debug, Hash, PartialEq, Clone) -)] -pub struct ComponentId(usize); - -impl ComponentId { - /// Creates a new [`ComponentId`]. - /// - /// The `index` is a unique value associated with each type of component in a given world. - /// Usually, this value is taken from a counter incremented for each type of component registered with the world. - #[inline] - pub const fn new(index: usize) -> ComponentId { - ComponentId(index) - } - - /// Returns the index of the current component. - #[inline] - pub fn index(self) -> usize { - self.0 - } -} - -impl SparseSetIndex for ComponentId { - #[inline] - fn sparse_set_index(&self) -> usize { - self.index() - } - - #[inline] - fn get_sparse_set_index(value: usize) -> Self { - Self(value) - } -} - -/// A value describing a component or resource, which may or may not correspond to a Rust type. -#[derive(Clone)] -pub struct ComponentDescriptor { - name: DebugName, - // SAFETY: This must remain private. It must match the statically known StorageType of the - // associated rust component type if one exists. - storage_type: StorageType, - // SAFETY: This must remain private. It must only be set to "true" if this component is - // actually Send + Sync - is_send_and_sync: bool, - type_id: Option, - layout: Layout, - // SAFETY: this function must be safe to call with pointers pointing to items of the type - // this descriptor describes. - // None if the underlying type doesn't need to be dropped - drop: Option unsafe fn(OwningPtr<'a>)>, - mutable: bool, - clone_behavior: ComponentCloneBehavior, -} - -// We need to ignore the `drop` field in our `Debug` impl -impl Debug for ComponentDescriptor { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("ComponentDescriptor") - .field("name", &self.name) - .field("storage_type", &self.storage_type) - .field("is_send_and_sync", &self.is_send_and_sync) - .field("type_id", &self.type_id) - .field("layout", &self.layout) - .field("mutable", &self.mutable) - .field("clone_behavior", &self.clone_behavior) - .finish() - } -} - -impl ComponentDescriptor { - /// # Safety - /// - /// `x` must point to a valid value of type `T`. - unsafe fn drop_ptr(x: OwningPtr<'_>) { - // SAFETY: Contract is required to be upheld by the caller. - unsafe { - x.drop_as::(); - } - } - - /// Create a new `ComponentDescriptor` for the type `T`. - pub fn new() -> Self { - Self { - name: DebugName::type_name::(), - storage_type: T::STORAGE_TYPE, - is_send_and_sync: true, - type_id: Some(TypeId::of::()), - layout: Layout::new::(), - drop: needs_drop::().then_some(Self::drop_ptr:: as _), - mutable: T::Mutability::MUTABLE, - clone_behavior: T::clone_behavior(), - } - } - - /// Create a new `ComponentDescriptor`. - /// - /// # Safety - /// - the `drop` fn must be usable on a pointer with a value of the layout `layout` - /// - the component type must be safe to access from any thread (Send + Sync in rust terms) - pub unsafe fn new_with_layout( - name: impl Into>, - storage_type: StorageType, - layout: Layout, - drop: Option unsafe fn(OwningPtr<'a>)>, - mutable: bool, - clone_behavior: ComponentCloneBehavior, - ) -> Self { - Self { - name: name.into().into(), - storage_type, - is_send_and_sync: true, - type_id: None, - layout, - drop, - mutable, - clone_behavior, - } - } - - /// Create a new `ComponentDescriptor` for a resource. - /// - /// The [`StorageType`] for resources is always [`StorageType::Table`]. - pub fn new_resource() -> Self { - Self { - name: DebugName::type_name::(), - // PERF: `SparseStorage` may actually be a more - // reasonable choice as `storage_type` for resources. - storage_type: StorageType::Table, - is_send_and_sync: true, - type_id: Some(TypeId::of::()), - layout: Layout::new::(), - drop: needs_drop::().then_some(Self::drop_ptr:: as _), - mutable: true, - clone_behavior: ComponentCloneBehavior::Default, - } - } - - fn new_non_send(storage_type: StorageType) -> Self { - Self { - name: DebugName::type_name::(), - storage_type, - is_send_and_sync: false, - type_id: Some(TypeId::of::()), - layout: Layout::new::(), - drop: needs_drop::().then_some(Self::drop_ptr:: as _), - mutable: true, - clone_behavior: ComponentCloneBehavior::Default, - } - } - - /// Returns a value indicating the storage strategy for the current component. - #[inline] - pub fn storage_type(&self) -> StorageType { - self.storage_type - } - - /// Returns the [`TypeId`] of the underlying component type. - /// Returns `None` if the component does not correspond to a Rust type. - #[inline] - pub fn type_id(&self) -> Option { - self.type_id - } - - /// Returns the name of the current component. - #[inline] - pub fn name(&self) -> DebugName { - self.name.clone() - } - - /// Returns whether this component is mutable. - #[inline] - pub fn mutable(&self) -> bool { - self.mutable - } -} - -/// Function type that can be used to clone an entity. -pub type ComponentCloneFn = fn(&SourceComponent, &mut ComponentCloneCtx); - -/// The clone behavior to use when cloning a [`Component`]. -#[derive(Clone, Debug, Default, PartialEq, Eq)] -pub enum ComponentCloneBehavior { - /// Uses the default behavior (which is passed to [`ComponentCloneBehavior::resolve`]) - #[default] - Default, - /// Do not clone this component. - Ignore, - /// Uses a custom [`ComponentCloneFn`]. - Custom(ComponentCloneFn), -} - -impl ComponentCloneBehavior { - /// Set clone handler based on `Clone` trait. - /// - /// If set as a handler for a component that is not the same as the one used to create this handler, it will panic. - pub fn clone() -> Self { - Self::Custom(component_clone_via_clone::) - } - - /// Set clone handler based on `Reflect` trait. - #[cfg(feature = "bevy_reflect")] - pub fn reflect() -> Self { - Self::Custom(component_clone_via_reflect) - } - - /// Returns the "global default" - pub fn global_default_fn() -> ComponentCloneFn { - #[cfg(feature = "bevy_reflect")] - return component_clone_via_reflect; - #[cfg(not(feature = "bevy_reflect"))] - return component_clone_ignore; - } - - /// Resolves the [`ComponentCloneBehavior`] to a [`ComponentCloneFn`]. If [`ComponentCloneBehavior::Default`] is - /// specified, the given `default` function will be used. - pub fn resolve(&self, default: ComponentCloneFn) -> ComponentCloneFn { - match self { - ComponentCloneBehavior::Default => default, - ComponentCloneBehavior::Ignore => component_clone_ignore, - ComponentCloneBehavior::Custom(custom) => *custom, - } - } -} - -/// A queued component registration. -struct QueuedRegistration { - registrator: Box, - id: ComponentId, - descriptor: ComponentDescriptor, -} - -impl QueuedRegistration { - /// Creates the [`QueuedRegistration`]. - /// - /// # Safety - /// - /// [`ComponentId`] must be unique. - unsafe fn new( - id: ComponentId, - descriptor: ComponentDescriptor, - func: impl FnOnce(&mut ComponentsRegistrator, ComponentId, ComponentDescriptor) + 'static, - ) -> Self { - Self { - registrator: Box::new(func), - id, - descriptor, - } - } - - /// Performs the registration, returning the now valid [`ComponentId`]. - fn register(self, registrator: &mut ComponentsRegistrator) -> ComponentId { - (self.registrator)(registrator, self.id, self.descriptor); - self.id - } -} - -/// Allows queuing components to be registered. -#[derive(Default)] -pub struct QueuedComponents { - components: TypeIdMap, - resources: TypeIdMap, - dynamic_registrations: Vec, -} - -impl Debug for QueuedComponents { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let components = self - .components - .iter() - .map(|(type_id, queued)| (type_id, queued.id)) - .collect::>(); - let resources = self - .resources - .iter() - .map(|(type_id, queued)| (type_id, queued.id)) - .collect::>(); - let dynamic_registrations = self - .dynamic_registrations - .iter() - .map(|queued| queued.id) - .collect::>(); - write!(f, "components: {components:?}, resources: {resources:?}, dynamic_registrations: {dynamic_registrations:?}") - } -} - -/// Generates [`ComponentId`]s. -#[derive(Debug, Default)] -pub struct ComponentIds { - next: bevy_platform::sync::atomic::AtomicUsize, -} - -impl ComponentIds { - /// Peeks the next [`ComponentId`] to be generated without generating it. - pub fn peek(&self) -> ComponentId { - ComponentId( - self.next - .load(bevy_platform::sync::atomic::Ordering::Relaxed), - ) - } - - /// Generates and returns the next [`ComponentId`]. - pub fn next(&self) -> ComponentId { - ComponentId( - self.next - .fetch_add(1, bevy_platform::sync::atomic::Ordering::Relaxed), - ) - } - - /// Peeks the next [`ComponentId`] to be generated without generating it. - pub fn peek_mut(&mut self) -> ComponentId { - ComponentId(*self.next.get_mut()) - } - - /// Generates and returns the next [`ComponentId`]. - pub fn next_mut(&mut self) -> ComponentId { - let id = self.next.get_mut(); - let result = ComponentId(*id); - *id += 1; - result - } - - /// Returns the number of [`ComponentId`]s generated. - pub fn len(&self) -> usize { - self.peek().0 - } - - /// Returns true if and only if no ids have been generated. - pub fn is_empty(&self) -> bool { - self.len() == 0 - } -} - -/// A type that enables queuing registration in [`Components`]. -/// -/// # Note -/// -/// These queued registrations return [`ComponentId`]s. -/// These ids are not yet valid, but they will become valid -/// when either [`ComponentsRegistrator::apply_queued_registrations`] is called or the same registration is made directly. -/// In either case, the returned [`ComponentId`]s will be correct, but they are not correct yet. -/// -/// Generally, that means these [`ComponentId`]s can be safely used for read-only purposes. -/// Modifying the contents of the world through these [`ComponentId`]s directly without waiting for them to be fully registered -/// and without then confirming that they have been fully registered is not supported. -/// Hence, extra care is needed with these [`ComponentId`]s to ensure all safety rules are followed. -/// -/// As a rule of thumb, if you have mutable access to [`ComponentsRegistrator`], prefer to use that instead. -/// Use this only if you need to know the id of a component but do not need to modify the contents of the world based on that id. -#[derive(Clone, Copy)] -pub struct ComponentsQueuedRegistrator<'w> { - components: &'w Components, - ids: &'w ComponentIds, -} - -impl Deref for ComponentsQueuedRegistrator<'_> { - type Target = Components; - - fn deref(&self) -> &Self::Target { - self.components - } -} - -impl<'w> ComponentsQueuedRegistrator<'w> { - /// Constructs a new [`ComponentsQueuedRegistrator`]. - /// - /// # Safety - /// - /// The [`Components`] and [`ComponentIds`] must match. - /// For example, they must be from the same world. - pub unsafe fn new(components: &'w Components, ids: &'w ComponentIds) -> Self { - Self { components, ids } - } - - /// Queues this function to run as a component registrator. - /// - /// # Safety - /// - /// The [`TypeId`] must not already be registered or queued as a component. - unsafe fn force_register_arbitrary_component( - &self, - type_id: TypeId, - descriptor: ComponentDescriptor, - func: impl FnOnce(&mut ComponentsRegistrator, ComponentId, ComponentDescriptor) + 'static, - ) -> ComponentId { - let id = self.ids.next(); - self.components - .queued - .write() - .unwrap_or_else(PoisonError::into_inner) - .components - .insert( - type_id, - // SAFETY: The id was just generated. - unsafe { QueuedRegistration::new(id, descriptor, func) }, - ); - id - } - - /// Queues this function to run as a resource registrator. - /// - /// # Safety - /// - /// The [`TypeId`] must not already be registered or queued as a resource. - unsafe fn force_register_arbitrary_resource( - &self, - type_id: TypeId, - descriptor: ComponentDescriptor, - func: impl FnOnce(&mut ComponentsRegistrator, ComponentId, ComponentDescriptor) + 'static, - ) -> ComponentId { - let id = self.ids.next(); - self.components - .queued - .write() - .unwrap_or_else(PoisonError::into_inner) - .resources - .insert( - type_id, - // SAFETY: The id was just generated. - unsafe { QueuedRegistration::new(id, descriptor, func) }, - ); - id - } - - /// Queues this function to run as a dynamic registrator. - fn force_register_arbitrary_dynamic( - &self, - descriptor: ComponentDescriptor, - func: impl FnOnce(&mut ComponentsRegistrator, ComponentId, ComponentDescriptor) + 'static, - ) -> ComponentId { - let id = self.ids.next(); - self.components - .queued - .write() - .unwrap_or_else(PoisonError::into_inner) - .dynamic_registrations - .push( - // SAFETY: The id was just generated. - unsafe { QueuedRegistration::new(id, descriptor, func) }, - ); - id - } - - /// This is a queued version of [`ComponentsRegistrator::register_component`]. - /// This will reserve an id and queue the registration. - /// These registrations will be carried out at the next opportunity. - /// - /// If this has already been registered or queued, this returns the previous [`ComponentId`]. - /// - /// # Note - /// - /// Technically speaking, the returned [`ComponentId`] is not valid, but it will become valid later. - /// See type level docs for details. - #[inline] - pub fn queue_register_component(&self) -> ComponentId { - self.component_id::().unwrap_or_else(|| { - // SAFETY: We just checked that this type was not in the queue. - unsafe { - self.force_register_arbitrary_component( - TypeId::of::(), - ComponentDescriptor::new::(), - |registrator, id, _descriptor| { - // SAFETY: We just checked that this is not currently registered or queued, and if it was registered since, this would have been dropped from the queue. - #[expect(unused_unsafe, reason = "More precise to specify.")] - unsafe { - registrator.register_component_unchecked::(&mut Vec::new(), id); - } - }, - ) - } - }) - } - - /// This is a queued version of [`ComponentsRegistrator::register_component_with_descriptor`]. - /// This will reserve an id and queue the registration. - /// These registrations will be carried out at the next opportunity. - /// - /// # Note - /// - /// Technically speaking, the returned [`ComponentId`] is not valid, but it will become valid later. - /// See type level docs for details. - #[inline] - pub fn queue_register_component_with_descriptor( - &self, - descriptor: ComponentDescriptor, - ) -> ComponentId { - self.force_register_arbitrary_dynamic(descriptor, |registrator, id, descriptor| { - // SAFETY: Id uniqueness handled by caller. - unsafe { - registrator.register_component_inner(id, descriptor); - } - }) - } - - /// This is a queued version of [`ComponentsRegistrator::register_resource`]. - /// This will reserve an id and queue the registration. - /// These registrations will be carried out at the next opportunity. - /// - /// If this has already been registered or queued, this returns the previous [`ComponentId`]. - /// - /// # Note - /// - /// Technically speaking, the returned [`ComponentId`] is not valid, but it will become valid later. - /// See type level docs for details. - #[inline] - pub fn queue_register_resource(&self) -> ComponentId { - let type_id = TypeId::of::(); - self.get_resource_id(type_id).unwrap_or_else(|| { - // SAFETY: We just checked that this type was not in the queue. - unsafe { - self.force_register_arbitrary_resource( - type_id, - ComponentDescriptor::new_resource::(), - move |registrator, id, descriptor| { - // SAFETY: We just checked that this is not currently registered or queued, and if it was registered since, this would have been dropped from the queue. - // SAFETY: Id uniqueness handled by caller, and the type_id matches descriptor. - #[expect(unused_unsafe, reason = "More precise to specify.")] - unsafe { - registrator.register_resource_unchecked(type_id, id, descriptor); - } - }, - ) - } - }) - } - - /// This is a queued version of [`ComponentsRegistrator::register_non_send`]. - /// This will reserve an id and queue the registration. - /// These registrations will be carried out at the next opportunity. - /// - /// If this has already been registered or queued, this returns the previous [`ComponentId`]. - /// - /// # Note - /// - /// Technically speaking, the returned [`ComponentId`] is not valid, but it will become valid later. - /// See type level docs for details. - #[inline] - pub fn queue_register_non_send(&self) -> ComponentId { - let type_id = TypeId::of::(); - self.get_resource_id(type_id).unwrap_or_else(|| { - // SAFETY: We just checked that this type was not in the queue. - unsafe { - self.force_register_arbitrary_resource( - type_id, - ComponentDescriptor::new_non_send::(StorageType::default()), - move |registrator, id, descriptor| { - // SAFETY: We just checked that this is not currently registered or queued, and if it was registered since, this would have been dropped from the queue. - // SAFETY: Id uniqueness handled by caller, and the type_id matches descriptor. - #[expect(unused_unsafe, reason = "More precise to specify.")] - unsafe { - registrator.register_resource_unchecked(type_id, id, descriptor); - } - }, - ) - } - }) - } - - /// This is a queued version of [`ComponentsRegistrator::register_resource_with_descriptor`]. - /// This will reserve an id and queue the registration. - /// These registrations will be carried out at the next opportunity. - /// - /// # Note - /// - /// Technically speaking, the returned [`ComponentId`] is not valid, but it will become valid later. - /// See type level docs for details. - #[inline] - pub fn queue_register_resource_with_descriptor( - &self, - descriptor: ComponentDescriptor, - ) -> ComponentId { - self.force_register_arbitrary_dynamic(descriptor, |registrator, id, descriptor| { - // SAFETY: Id uniqueness handled by caller. - unsafe { - registrator.register_component_inner(id, descriptor); - } - }) - } -} - -/// A [`Components`] wrapper that enables additional features, like registration. -pub struct ComponentsRegistrator<'w> { - components: &'w mut Components, - ids: &'w mut ComponentIds, -} - -impl Deref for ComponentsRegistrator<'_> { - type Target = Components; - - fn deref(&self) -> &Self::Target { - self.components - } -} - -impl DerefMut for ComponentsRegistrator<'_> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.components - } -} - -impl<'w> ComponentsRegistrator<'w> { - /// Constructs a new [`ComponentsRegistrator`]. - /// - /// # Safety - /// - /// The [`Components`] and [`ComponentIds`] must match. - /// For example, they must be from the same world. - pub unsafe fn new(components: &'w mut Components, ids: &'w mut ComponentIds) -> Self { - Self { components, ids } - } - - /// Converts this [`ComponentsRegistrator`] into a [`ComponentsQueuedRegistrator`]. - /// This is intended for use to pass this value to a function that requires [`ComponentsQueuedRegistrator`]. - /// It is generally not a good idea to queue a registration when you can instead register directly on this type. - pub fn as_queued(&self) -> ComponentsQueuedRegistrator<'_> { - // SAFETY: ensured by the caller that created self. - unsafe { ComponentsQueuedRegistrator::new(self.components, self.ids) } - } - - /// Applies every queued registration. - /// This ensures that every valid [`ComponentId`] is registered, - /// enabling retrieving [`ComponentInfo`], etc. - pub fn apply_queued_registrations(&mut self) { - if !self.any_queued_mut() { - return; - } - - // Note: - // - // This is not just draining the queue. We need to empty the queue without removing the information from `Components`. - // If we drained directly, we could break invariance. - // - // For example, say `ComponentA` and `ComponentB` are queued, and `ComponentA` requires `ComponentB`. - // If we drain directly, and `ComponentA` was the first to be registered, then, when `ComponentA` - // registers `ComponentB` in `Component::register_required_components`, - // `Components` will not know that `ComponentB` was queued - // (since it will have been drained from the queue.) - // If that happened, `Components` would assign a new `ComponentId` to `ComponentB` - // which would be *different* than the id it was assigned in the queue. - // Then, when the drain iterator gets to `ComponentB`, - // it would be unsafely registering `ComponentB`, which is already registered. - // - // As a result, we need to pop from each queue one by one instead of draining. - - // components - while let Some(registrator) = { - let queued = self - .components - .queued - .get_mut() - .unwrap_or_else(PoisonError::into_inner); - queued.components.keys().next().copied().map(|type_id| { - // SAFETY: the id just came from a valid iterator. - unsafe { queued.components.remove(&type_id).debug_checked_unwrap() } - }) - } { - registrator.register(self); - } - - // resources - while let Some(registrator) = { - let queued = self - .components - .queued - .get_mut() - .unwrap_or_else(PoisonError::into_inner); - queued.resources.keys().next().copied().map(|type_id| { - // SAFETY: the id just came from a valid iterator. - unsafe { queued.resources.remove(&type_id).debug_checked_unwrap() } - }) - } { - registrator.register(self); - } - - // dynamic - let queued = &mut self - .components - .queued - .get_mut() - .unwrap_or_else(PoisonError::into_inner); - if !queued.dynamic_registrations.is_empty() { - for registrator in core::mem::take(&mut queued.dynamic_registrations) { - registrator.register(self); - } - } - } - - /// Registers a [`Component`] of type `T` with this instance. - /// If a component of this type has already been registered, this will return - /// the ID of the pre-existing component. - /// - /// # See also - /// - /// * [`Components::component_id()`] - /// * [`ComponentsRegistrator::register_component_with_descriptor()`] - #[inline] - pub fn register_component(&mut self) -> ComponentId { - self.register_component_checked::(&mut Vec::new()) - } - - /// Same as [`Self::register_component_unchecked`] but keeps a checks for safety. - #[inline] - fn register_component_checked( - &mut self, - recursion_check_stack: &mut Vec, - ) -> ComponentId { - let type_id = TypeId::of::(); - if let Some(id) = self.indices.get(&type_id) { - return *id; - } - - if let Some(registrator) = self - .components - .queued - .get_mut() - .unwrap_or_else(PoisonError::into_inner) - .components - .remove(&type_id) - { - // If we are trying to register something that has already been queued, we respect the queue. - // Just like if we are trying to register something that already is, we respect the first registration. - return registrator.register(self); - } - - let id = self.ids.next_mut(); - // SAFETY: The component is not currently registered, and the id is fresh. - unsafe { - self.register_component_unchecked::(recursion_check_stack, id); - } - id - } - - /// # Safety - /// - /// Neither this component, nor its id may be registered or queued. This must be a new registration. - #[inline] - unsafe fn register_component_unchecked( - &mut self, - recursion_check_stack: &mut Vec, - id: ComponentId, - ) { - // SAFETY: ensured by caller. - unsafe { - self.register_component_inner(id, ComponentDescriptor::new::()); - } - let type_id = TypeId::of::(); - let prev = self.indices.insert(type_id, id); - debug_assert!(prev.is_none()); - - let mut required_components = RequiredComponents::default(); - T::register_required_components( - id, - self, - &mut required_components, - 0, - recursion_check_stack, - ); - // SAFETY: we just inserted it in `register_component_inner` - let info = unsafe { - &mut self - .components - .components - .get_mut(id.0) - .debug_checked_unwrap() - .as_mut() - .debug_checked_unwrap() - }; - - info.hooks.update_from_component::(); - - info.required_components = required_components; - } - - /// Registers a component described by `descriptor`. - /// - /// # Note - /// - /// If this method is called multiple times with identical descriptors, a distinct [`ComponentId`] - /// will be created for each one. - /// - /// # See also - /// - /// * [`Components::component_id()`] - /// * [`ComponentsRegistrator::register_component()`] - #[inline] - pub fn register_component_with_descriptor( - &mut self, - descriptor: ComponentDescriptor, - ) -> ComponentId { - let id = self.ids.next_mut(); - // SAFETY: The id is fresh. - unsafe { - self.register_component_inner(id, descriptor); - } - 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( - &mut self, - required_components: &mut RequiredComponents, - constructor: fn() -> R, - inheritance_depth: u16, - recursion_check_stack: &mut Vec, - ) { - let requiree = self.register_component_checked::(recursion_check_stack); - let required = self.register_component_checked::(recursion_check_stack); - - // SAFETY: We just created the components. - unsafe { - self.register_required_components_manual_unchecked::( - 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. - /// - /// # See also - /// - /// * [`Components::resource_id()`] - /// * [`ComponentsRegistrator::register_resource_with_descriptor()`] - #[inline] - pub fn register_resource(&mut self) -> ComponentId { - // SAFETY: The [`ComponentDescriptor`] matches the [`TypeId`] - unsafe { - self.register_resource_with(TypeId::of::(), || { - ComponentDescriptor::new_resource::() - }) - } - } - - /// Registers a [non-send resource](crate::system::NonSend) 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. - #[inline] - pub fn register_non_send(&mut self) -> ComponentId { - // SAFETY: The [`ComponentDescriptor`] matches the [`TypeId`] - unsafe { - self.register_resource_with(TypeId::of::(), || { - ComponentDescriptor::new_non_send::(StorageType::default()) - }) - } - } - - /// Same as [`Components::register_resource_unchecked`] but handles safety. - /// - /// # Safety - /// - /// The [`ComponentDescriptor`] must match the [`TypeId`]. - #[inline] - unsafe fn register_resource_with( - &mut self, - type_id: TypeId, - descriptor: impl FnOnce() -> ComponentDescriptor, - ) -> ComponentId { - if let Some(id) = self.resource_indices.get(&type_id) { - return *id; - } - - if let Some(registrator) = self - .components - .queued - .get_mut() - .unwrap_or_else(PoisonError::into_inner) - .resources - .remove(&type_id) - { - // If we are trying to register something that has already been queued, we respect the queue. - // Just like if we are trying to register something that already is, we respect the first registration. - return registrator.register(self); - } - - let id = self.ids.next_mut(); - // SAFETY: The resource is not currently registered, the id is fresh, and the [`ComponentDescriptor`] matches the [`TypeId`] - unsafe { - self.register_resource_unchecked(type_id, id, descriptor()); - } - id - } - - /// Registers a [`Resource`] described by `descriptor`. - /// - /// # Note - /// - /// If this method is called multiple times with identical descriptors, a distinct [`ComponentId`] - /// will be created for each one. - /// - /// # See also - /// - /// * [`Components::resource_id()`] - /// * [`ComponentsRegistrator::register_resource()`] - #[inline] - pub fn register_resource_with_descriptor( - &mut self, - descriptor: ComponentDescriptor, - ) -> ComponentId { - let id = self.ids.next_mut(); - // SAFETY: The id is fresh. - unsafe { - self.register_component_inner(id, descriptor); - } - id - } -} - -/// Stores metadata associated with each kind of [`Component`] in a given [`World`]. -#[derive(Debug, Default)] -pub struct Components { - components: Vec>, - indices: TypeIdMap, - resource_indices: TypeIdMap, - // This is kept internal and local to verify that no deadlocks can occor. - queued: bevy_platform::sync::RwLock, -} - -impl Components { - /// This registers any descriptor, component or resource. - /// - /// # Safety - /// - /// The id must have never been registered before. This must be a fresh registration. - #[inline] - unsafe fn register_component_inner( - &mut self, - id: ComponentId, - descriptor: ComponentDescriptor, - ) { - let info = ComponentInfo::new(id, descriptor); - let least_len = id.0 + 1; - if self.components.len() < least_len { - self.components.resize_with(least_len, || None); - } - // SAFETY: We just extended the vec to make this index valid. - let slot = unsafe { self.components.get_mut(id.0).debug_checked_unwrap() }; - // Caller ensures id is unique - debug_assert!(slot.is_none()); - *slot = Some(info); - } - - /// Returns the number of components registered or queued with this instance. - #[inline] - pub fn len(&self) -> usize { - self.num_queued() + self.num_registered() - } - - /// Returns `true` if there are no components registered or queued with this instance. Otherwise, this returns `false`. - #[inline] - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Returns the number of components registered with this instance. - #[inline] - pub fn num_queued(&self) -> usize { - let queued = self.queued.read().unwrap_or_else(PoisonError::into_inner); - queued.components.len() + queued.dynamic_registrations.len() + queued.resources.len() - } - - /// Returns `true` if there are any components registered with this instance. Otherwise, this returns `false`. - #[inline] - pub fn any_queued(&self) -> bool { - self.num_queued() > 0 - } - - /// A faster version of [`Self::num_queued`]. - #[inline] - pub fn num_queued_mut(&mut self) -> usize { - let queued = self - .queued - .get_mut() - .unwrap_or_else(PoisonError::into_inner); - queued.components.len() + queued.dynamic_registrations.len() + queued.resources.len() - } - - /// A faster version of [`Self::any_queued`]. - #[inline] - pub fn any_queued_mut(&mut self) -> bool { - self.num_queued_mut() > 0 - } - - /// Returns the number of components registered with this instance. - #[inline] - pub fn num_registered(&self) -> usize { - self.components.len() - } - - /// Returns `true` if there are any components registered with this instance. Otherwise, this returns `false`. - #[inline] - pub fn any_registered(&self) -> bool { - self.num_registered() > 0 - } - - /// Gets the metadata associated with the given component, if it is registered. - /// This will return `None` if the id is not registered or is queued. - /// - /// This will return an incorrect result if `id` did not come from the same world as `self`. It may return `None` or a garbage value. - #[inline] - pub fn get_info(&self, id: ComponentId) -> Option<&ComponentInfo> { - self.components.get(id.0).and_then(|info| info.as_ref()) - } - - /// Gets the [`ComponentDescriptor`] of the component with this [`ComponentId`] if it is present. - /// This will return `None` only if the id is neither registered nor queued to be registered. - /// - /// Currently, the [`Cow`] will be [`Cow::Owned`] if and only if the component is queued. It will be [`Cow::Borrowed`] otherwise. - /// - /// This will return an incorrect result if `id` did not come from the same world as `self`. It may return `None` or a garbage value. - #[inline] - pub fn get_descriptor<'a>(&'a self, id: ComponentId) -> Option> { - self.components - .get(id.0) - .and_then(|info| info.as_ref().map(|info| Cow::Borrowed(&info.descriptor))) - .or_else(|| { - let queued = self.queued.read().unwrap_or_else(PoisonError::into_inner); - // first check components, then resources, then dynamic - queued - .components - .values() - .chain(queued.resources.values()) - .chain(queued.dynamic_registrations.iter()) - .find(|queued| queued.id == id) - .map(|queued| Cow::Owned(queued.descriptor.clone())) - }) - } - - /// Gets the name of the component with this [`ComponentId`] if it is present. - /// This will return `None` only if the id is neither registered nor queued to be registered. - /// - /// This will return an incorrect result if `id` did not come from the same world as `self`. It may return `None` or a garbage value. - #[inline] - pub fn get_name<'a>(&'a self, id: ComponentId) -> Option { - self.components - .get(id.0) - .and_then(|info| info.as_ref().map(|info| info.descriptor.name())) - .or_else(|| { - let queued = self.queued.read().unwrap_or_else(PoisonError::into_inner); - // first check components, then resources, then dynamic - queued - .components - .values() - .chain(queued.resources.values()) - .chain(queued.dynamic_registrations.iter()) - .find(|queued| queued.id == id) - .map(|queued| queued.descriptor.name.clone()) - }) - } - - /// Gets the metadata associated with the given component. - /// # Safety - /// - /// `id` must be a valid and fully registered [`ComponentId`]. - #[inline] - pub unsafe fn get_info_unchecked(&self, id: ComponentId) -> &ComponentInfo { - // SAFETY: The caller ensures `id` is valid. - unsafe { - self.components - .get(id.0) - .debug_checked_unwrap() - .as_ref() - .debug_checked_unwrap() - } - } - - #[inline] - pub(crate) fn get_hooks_mut(&mut self, id: ComponentId) -> Option<&mut ComponentHooks> { - self.components - .get_mut(id.0) - .and_then(|info| info.as_mut().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) - .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( - &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::>()) - { - // `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( - &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> { - self.components - .get(id.0) - .and_then(|info| info.as_ref().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) - .and_then(|info| info.as_mut().map(|info| &mut info.required_by)) - } - - /// Returns true if the [`ComponentId`] is fully registered and valid. - /// Ids may be invalid if they are still queued to be registered. - /// Those ids are still correct, but they are not usable in every context yet. - #[inline] - pub fn is_id_valid(&self, id: ComponentId) -> bool { - self.components.get(id.0).is_some_and(Option::is_some) - } - - /// Type-erased equivalent of [`Components::valid_component_id()`]. - #[inline] - pub fn get_valid_id(&self, type_id: TypeId) -> Option { - self.indices.get(&type_id).copied() - } - - /// Returns the [`ComponentId`] of the given [`Component`] type `T` if it is fully registered. - /// If you want to include queued registration, see [`Components::component_id()`]. - /// - /// ``` - /// use bevy_ecs::prelude::*; - /// - /// let mut world = World::new(); - /// - /// #[derive(Component)] - /// struct ComponentA; - /// - /// let component_a_id = world.register_component::(); - /// - /// assert_eq!(component_a_id, world.components().valid_component_id::().unwrap()) - /// ``` - /// - /// # See also - /// - /// * [`Components::get_valid_id()`] - /// * [`Components::valid_resource_id()`] - /// * [`World::component_id()`] - #[inline] - pub fn valid_component_id(&self) -> Option { - self.get_valid_id(TypeId::of::()) - } - - /// Type-erased equivalent of [`Components::valid_resource_id()`]. - #[inline] - pub fn get_valid_resource_id(&self, type_id: TypeId) -> Option { - self.resource_indices.get(&type_id).copied() - } - - /// Returns the [`ComponentId`] of the given [`Resource`] type `T` if it is fully registered. - /// If you want to include queued registration, see [`Components::resource_id()`]. - /// - /// ``` - /// use bevy_ecs::prelude::*; - /// - /// let mut world = World::new(); - /// - /// #[derive(Resource, Default)] - /// struct ResourceA; - /// - /// let resource_a_id = world.init_resource::(); - /// - /// assert_eq!(resource_a_id, world.components().valid_resource_id::().unwrap()) - /// ``` - /// - /// # See also - /// - /// * [`Components::valid_component_id()`] - /// * [`Components::get_resource_id()`] - #[inline] - pub fn valid_resource_id(&self) -> Option { - self.get_valid_resource_id(TypeId::of::()) - } - - /// Type-erased equivalent of [`Components::component_id()`]. - #[inline] - pub fn get_id(&self, type_id: TypeId) -> Option { - self.indices.get(&type_id).copied().or_else(|| { - self.queued - .read() - .unwrap_or_else(PoisonError::into_inner) - .components - .get(&type_id) - .map(|queued| queued.id) - }) - } - - /// Returns the [`ComponentId`] of the given [`Component`] type `T`. - /// - /// The returned `ComponentId` is specific to the `Components` instance - /// it was retrieved from and should not be used with another `Components` - /// instance. - /// - /// Returns [`None`] if the `Component` type has not - /// yet been initialized using [`ComponentsRegistrator::register_component()`] or [`ComponentsQueuedRegistrator::queue_register_component()`]. - /// - /// ``` - /// use bevy_ecs::prelude::*; - /// - /// let mut world = World::new(); - /// - /// #[derive(Component)] - /// struct ComponentA; - /// - /// let component_a_id = world.register_component::(); - /// - /// assert_eq!(component_a_id, world.components().component_id::().unwrap()) - /// ``` - /// - /// # See also - /// - /// * [`Components::get_id()`] - /// * [`Components::resource_id()`] - /// * [`World::component_id()`] - #[inline] - pub fn component_id(&self) -> Option { - self.get_id(TypeId::of::()) - } - - /// Type-erased equivalent of [`Components::resource_id()`]. - #[inline] - pub fn get_resource_id(&self, type_id: TypeId) -> Option { - self.resource_indices.get(&type_id).copied().or_else(|| { - self.queued - .read() - .unwrap_or_else(PoisonError::into_inner) - .resources - .get(&type_id) - .map(|queued| queued.id) - }) - } - - /// Returns the [`ComponentId`] of the given [`Resource`] type `T`. - /// - /// The returned `ComponentId` is specific to the `Components` instance - /// it was retrieved from and should not be used with another `Components` - /// instance. - /// - /// Returns [`None`] if the `Resource` type has not - /// yet been initialized using [`ComponentsRegistrator::register_resource()`] or [`ComponentsQueuedRegistrator::queue_register_resource()`]. - /// - /// ``` - /// use bevy_ecs::prelude::*; - /// - /// let mut world = World::new(); - /// - /// #[derive(Resource, Default)] - /// struct ResourceA; - /// - /// let resource_a_id = world.init_resource::(); - /// - /// assert_eq!(resource_a_id, world.components().resource_id::().unwrap()) - /// ``` - /// - /// # See also - /// - /// * [`Components::component_id()`] - /// * [`Components::get_resource_id()`] - #[inline] - pub fn resource_id(&self) -> Option { - self.get_resource_id(TypeId::of::()) - } - - /// # Safety - /// - /// The [`ComponentDescriptor`] must match the [`TypeId`]. - /// The [`ComponentId`] must be unique. - /// The [`TypeId`] and [`ComponentId`] must not be registered or queued. - #[inline] - unsafe fn register_resource_unchecked( - &mut self, - type_id: TypeId, - component_id: ComponentId, - descriptor: ComponentDescriptor, - ) { - // SAFETY: ensured by caller - unsafe { - self.register_component_inner(component_id, descriptor); - } - let prev = self.resource_indices.insert(type_id, component_id); - debug_assert!(prev.is_none()); - } - - /// Gets an iterator over all components fully registered with this instance. - pub fn iter_registered(&self) -> impl Iterator + '_ { - self.components.iter().filter_map(Option::as_ref) - } -} - -/// A value that tracks when a system ran relative to other systems. -/// This is used to power change detection. -/// -/// *Note* that a system that hasn't been run yet has a `Tick` of 0. -#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq)] -#[cfg_attr( - feature = "bevy_reflect", - derive(Reflect), - reflect(Debug, Hash, PartialEq, Clone) -)] -pub struct Tick { - tick: u32, -} - -impl Tick { - /// The maximum relative age for a change tick. - /// The value of this is equal to [`MAX_CHANGE_AGE`]. - /// - /// Since change detection will not work for any ticks older than this, - /// ticks are periodically scanned to ensure their relative values are below this. - pub const MAX: Self = Self::new(MAX_CHANGE_AGE); - - /// Creates a new [`Tick`] wrapping the given value. - #[inline] - pub const fn new(tick: u32) -> Self { - Self { tick } - } - - /// Gets the value of this change tick. - #[inline] - pub const fn get(self) -> u32 { - self.tick - } - - /// Sets the value of this change tick. - #[inline] - pub fn set(&mut self, tick: u32) { - self.tick = tick; - } - - /// Returns `true` if this `Tick` occurred since the system's `last_run`. - /// - /// `this_run` is the current tick of the system, used as a reference to help deal with wraparound. - #[inline] - pub fn is_newer_than(self, last_run: Tick, this_run: Tick) -> bool { - // This works even with wraparound because the world tick (`this_run`) is always "newer" than - // `last_run` and `self.tick`, and we scan periodically to clamp `ComponentTicks` values - // so they never get older than `u32::MAX` (the difference would overflow). - // - // The clamp here ensures determinism (since scans could differ between app runs). - let ticks_since_insert = this_run.relative_to(self).tick.min(MAX_CHANGE_AGE); - let ticks_since_system = this_run.relative_to(last_run).tick.min(MAX_CHANGE_AGE); - - ticks_since_system > ticks_since_insert - } - - /// Returns a change tick representing the relationship between `self` and `other`. - #[inline] - pub(crate) fn relative_to(self, other: Self) -> Self { - let tick = self.tick.wrapping_sub(other.tick); - Self { tick } - } - - /// Wraps this change tick's value if it exceeds [`Tick::MAX`]. - /// - /// Returns `true` if wrapping was performed. Otherwise, returns `false`. - #[inline] - pub fn check_tick(&mut self, check: CheckChangeTicks) -> bool { - let age = check.present_tick().relative_to(*self); - // This comparison assumes that `age` has not overflowed `u32::MAX` before, which will be true - // so long as this check always runs before that can happen. - if age.get() > Self::MAX.get() { - *self = check.present_tick().relative_to(Self::MAX); - true - } else { - false - } - } -} - -/// An observer [`Event`] that can be used to maintain [`Tick`]s in custom data structures, enabling to make -/// use of bevy's periodic checks that clamps ticks to a certain range, preventing overflows and thus -/// keeping methods like [`Tick::is_newer_than`] reliably return `false` for ticks that got too old. -/// -/// # Example -/// -/// Here a schedule is stored in a custom resource. This way the systems in it would not have their change -/// ticks automatically updated via [`World::check_change_ticks`], possibly causing `Tick`-related bugs on -/// long-running apps. -/// -/// To fix that, add an observer for this event that calls the schedule's -/// [`Schedule::check_change_ticks`](bevy_ecs::schedule::Schedule::check_change_ticks). -/// -/// ``` -/// use bevy_ecs::prelude::*; -/// use bevy_ecs::component::CheckChangeTicks; -/// -/// #[derive(Resource)] -/// struct CustomSchedule(Schedule); -/// -/// # let mut world = World::new(); -/// world.add_observer(|check: On, mut schedule: ResMut| { -/// schedule.0.check_change_ticks(*check); -/// }); -/// ``` -#[derive(Debug, Clone, Copy, Event)] -pub struct CheckChangeTicks(pub(crate) Tick); - -impl CheckChangeTicks { - /// Get the present `Tick` that other ticks get compared to. - pub fn present_tick(self) -> Tick { - self.0 - } -} - -/// Interior-mutable access to the [`Tick`]s for a single component or resource. -#[derive(Copy, Clone, Debug)] -pub struct TickCells<'a> { - /// The tick indicating when the value was added to the world. - pub added: &'a UnsafeCell, - /// The tick indicating the last time the value was modified. - pub changed: &'a UnsafeCell, -} - -impl<'a> TickCells<'a> { - /// # Safety - /// All cells contained within must uphold the safety invariants of [`UnsafeCellDeref::read`]. - #[inline] - pub(crate) unsafe fn read(&self) -> ComponentTicks { - ComponentTicks { - // SAFETY: The callers uphold the invariants for `read`. - added: unsafe { self.added.read() }, - // SAFETY: The callers uphold the invariants for `read`. - changed: unsafe { self.changed.read() }, - } - } -} - -/// Records when a component or resource was added and when it was last mutably dereferenced (or added). -#[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, Clone))] -pub struct ComponentTicks { - /// Tick recording the time this component or resource was added. - pub added: Tick, - - /// Tick recording the time this component or resource was most recently changed. - pub changed: Tick, -} - -impl ComponentTicks { - /// Returns `true` if the component or resource was added after the system last ran - /// (or the system is running for the first time). - #[inline] - pub fn is_added(&self, last_run: Tick, this_run: Tick) -> bool { - self.added.is_newer_than(last_run, this_run) - } - - /// Returns `true` if the component or resource was added or mutably dereferenced after the system last ran - /// (or the system is running for the first time). - #[inline] - pub fn is_changed(&self, last_run: Tick, this_run: Tick) -> bool { - self.changed.is_newer_than(last_run, this_run) - } - - /// Creates a new instance with the same change tick for `added` and `changed`. - pub fn new(change_tick: Tick) -> Self { - Self { - added: change_tick, - changed: change_tick, - } - } - - /// Manually sets the change tick. - /// - /// This is normally done automatically via the [`DerefMut`] implementation - /// on [`Mut`](crate::change_detection::Mut), [`ResMut`](crate::change_detection::ResMut), etc. - /// However, components and resources that make use of interior mutability might require manual updates. - /// - /// # Example - /// ```no_run - /// # use bevy_ecs::{world::World, component::ComponentTicks}; - /// let world: World = unimplemented!(); - /// let component_ticks: ComponentTicks = unimplemented!(); - /// - /// component_ticks.set_changed(world.read_change_tick()); - /// ``` - #[inline] - pub fn set_changed(&mut self, change_tick: Tick) { - self.changed = change_tick; - } -} - -/// A [`SystemParam`] that provides access to the [`ComponentId`] for a specific component type. -/// -/// # Example -/// ``` -/// # use bevy_ecs::{system::Local, component::{Component, ComponentId, ComponentIdFor}}; -/// #[derive(Component)] -/// struct Player; -/// fn my_system(component_id: ComponentIdFor) { -/// let component_id: ComponentId = component_id.get(); -/// // ... -/// } -/// ``` -#[derive(SystemParam)] -pub struct ComponentIdFor<'s, T: Component>(Local<'s, InitComponentId>); - -impl ComponentIdFor<'_, T> { - /// Gets the [`ComponentId`] for the type `T`. - #[inline] - pub fn get(&self) -> ComponentId { - **self - } -} - -impl Deref for ComponentIdFor<'_, T> { - type Target = ComponentId; - fn deref(&self) -> &Self::Target { - &self.0.component_id - } -} - -impl From> for ComponentId { - #[inline] - fn from(to_component_id: ComponentIdFor) -> ComponentId { - *to_component_id - } -} - -/// Initializes the [`ComponentId`] for a specific type when used with [`FromWorld`]. -struct InitComponentId { - component_id: ComponentId, - marker: PhantomData, -} - -impl FromWorld for InitComponentId { - fn from_world(world: &mut World) -> Self { - Self { - component_id: world.register_component::(), - marker: PhantomData, - } - } -} - -/// 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, -); - -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); - -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( - &mut self, - components: &mut ComponentsRegistrator, - constructor: fn() -> C, - inheritance_depth: u16, - ) { - let component_id = components.register_component::(); - 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({ - // `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 = Box; - - #[cfg(target_has_atomic = "ptr")] - type Intermediate = Arc; - - let boxed: Intermediate = 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 + '_ { - 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::>() - .join(" → "), - if direct_recursion { - format!( - "Remove require({}).", - components.get_name(requiree).unwrap().shortname() - ) - } else { - "If this is intentional, consider merging the components.".into() - } - ); - } - } -} - -/// Component [clone handler function](ComponentCloneFn) implemented using the [`Clone`] trait. -/// Can be [set](Component::clone_behavior) as clone handler for the specific component it is implemented for. -/// It will panic if set as handler for any other component. -/// -pub fn component_clone_via_clone( - source: &SourceComponent, - ctx: &mut ComponentCloneCtx, -) { - if let Some(component) = source.read::() { - ctx.write_target_component(component.clone()); - } -} - -/// Component [clone handler function](ComponentCloneFn) implemented using reflect. -/// Can be [set](Component::clone_behavior) as clone handler for any registered component, -/// but only reflected components will be cloned. -/// -/// To clone a component using this handler, the following must be true: -/// - World has [`AppTypeRegistry`](crate::reflect::AppTypeRegistry) -/// - Component has [`TypeId`] -/// - Component is registered -/// - Component has [`ReflectFromPtr`](bevy_reflect::ReflectFromPtr) registered -/// - Component can be cloned via [`PartialReflect::reflect_clone`] _or_ has one of the following registered: [`ReflectFromReflect`](bevy_reflect::ReflectFromReflect), -/// [`ReflectDefault`](bevy_reflect::std_traits::ReflectDefault), [`ReflectFromWorld`](crate::reflect::ReflectFromWorld) -/// -/// If any of the conditions is not satisfied, the component will be skipped. -/// -/// See [`EntityClonerBuilder`](crate::entity::EntityClonerBuilder) for details. -/// -/// [`PartialReflect::reflect_clone`]: bevy_reflect::PartialReflect::reflect_clone -#[cfg(feature = "bevy_reflect")] -pub fn component_clone_via_reflect(source: &SourceComponent, ctx: &mut ComponentCloneCtx) { - let Some(app_registry) = ctx.type_registry().cloned() else { - return; - }; - let registry = app_registry.read(); - let Some(source_component_reflect) = source.read_reflect(®istry) else { - return; - }; - let component_info = ctx.component_info(); - // checked in read_source_component_reflect - let type_id = component_info.type_id().unwrap(); - - // Try to clone using `reflect_clone` - if let Ok(mut component) = source_component_reflect.reflect_clone() { - if let Some(reflect_component) = - registry.get_type_data::(type_id) - { - reflect_component.map_entities(&mut *component, ctx.entity_mapper()); - } - drop(registry); - - ctx.write_target_component_reflect(component); - return; - } - - // Try to clone using ReflectFromReflect - if let Some(reflect_from_reflect) = - registry.get_type_data::(type_id) - { - if let Some(mut component) = - reflect_from_reflect.from_reflect(source_component_reflect.as_partial_reflect()) - { - if let Some(reflect_component) = - registry.get_type_data::(type_id) - { - reflect_component.map_entities(&mut *component, ctx.entity_mapper()); - } - drop(registry); - - ctx.write_target_component_reflect(component); - return; - } - } - // Else, try to clone using ReflectDefault - if let Some(reflect_default) = - registry.get_type_data::(type_id) - { - let mut component = reflect_default.default(); - component.apply(source_component_reflect.as_partial_reflect()); - drop(registry); - ctx.write_target_component_reflect(component); - return; - } - // Otherwise, try to clone using ReflectFromWorld - if let Some(reflect_from_world) = - registry.get_type_data::(type_id) - { - let reflect_from_world = reflect_from_world.clone(); - let source_component_cloned = source_component_reflect.to_dynamic(); - let component_layout = component_info.layout(); - let target = ctx.target(); - let component_id = ctx.component_id(); - drop(registry); - ctx.queue_deferred(move |world: &mut World, mapper: &mut dyn EntityMapper| { - let mut component = reflect_from_world.from_world(world); - assert_eq!(type_id, (*component).type_id()); - component.apply(source_component_cloned.as_partial_reflect()); - if let Some(reflect_component) = app_registry - .read() - .get_type_data::(type_id) - { - reflect_component.map_entities(&mut *component, mapper); - } - // SAFETY: - // - component_id is from the same world as target entity - // - component is a valid value represented by component_id - unsafe { - let raw_component_ptr = - core::ptr::NonNull::new_unchecked(Box::into_raw(component).cast::()); - world - .entity_mut(target) - .insert_by_id(component_id, OwningPtr::new(raw_component_ptr)); - - if component_layout.size() > 0 { - // Ensure we don't attempt to deallocate zero-sized components - alloc::alloc::dealloc(raw_component_ptr.as_ptr(), component_layout); - } - } - }); - } -} - -/// Noop implementation of component clone handler function. -/// -/// See [`EntityClonerBuilder`](crate::entity::EntityClonerBuilder) for details. -pub fn component_clone_ignore(_source: &SourceComponent, _ctx: &mut ComponentCloneCtx) {} - -/// Wrapper for components clone specialization using autoderef. -#[doc(hidden)] -pub struct DefaultCloneBehaviorSpecialization(PhantomData); - -impl Default for DefaultCloneBehaviorSpecialization { - fn default() -> Self { - Self(PhantomData) - } -} - -/// Base trait for components clone specialization using autoderef. -#[doc(hidden)] -pub trait DefaultCloneBehaviorBase { - fn default_clone_behavior(&self) -> ComponentCloneBehavior; -} - -impl DefaultCloneBehaviorBase for DefaultCloneBehaviorSpecialization { - fn default_clone_behavior(&self) -> ComponentCloneBehavior { - ComponentCloneBehavior::Default - } -} - -/// Specialized trait for components clone specialization using autoderef. -#[doc(hidden)] -pub trait DefaultCloneBehaviorViaClone { - fn default_clone_behavior(&self) -> ComponentCloneBehavior; -} - -impl DefaultCloneBehaviorViaClone for &DefaultCloneBehaviorSpecialization { - fn default_clone_behavior(&self) -> ComponentCloneBehavior { - ComponentCloneBehavior::clone::() - } -} diff --git a/crates/bevy_ecs/src/component/clone.rs b/crates/bevy_ecs/src/component/clone.rs new file mode 100644 index 0000000000..ecbc6e60e5 --- /dev/null +++ b/crates/bevy_ecs/src/component/clone.rs @@ -0,0 +1,219 @@ +use core::marker::PhantomData; + +use crate::component::Component; +use crate::entity::{ComponentCloneCtx, SourceComponent}; + +/// Function type that can be used to clone an entity. +pub type ComponentCloneFn = fn(&SourceComponent, &mut ComponentCloneCtx); + +/// The clone behavior to use when cloning a [`Component`]. +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub enum ComponentCloneBehavior { + /// Uses the default behavior (which is passed to [`ComponentCloneBehavior::resolve`]) + #[default] + Default, + /// Do not clone this component. + Ignore, + /// Uses a custom [`ComponentCloneFn`]. + Custom(ComponentCloneFn), +} + +impl ComponentCloneBehavior { + /// Set clone handler based on `Clone` trait. + /// + /// If set as a handler for a component that is not the same as the one used to create this handler, it will panic. + pub fn clone() -> Self { + Self::Custom(component_clone_via_clone::) + } + + /// Set clone handler based on `Reflect` trait. + #[cfg(feature = "bevy_reflect")] + pub fn reflect() -> Self { + Self::Custom(component_clone_via_reflect) + } + + /// Returns the "global default" + pub fn global_default_fn() -> ComponentCloneFn { + #[cfg(feature = "bevy_reflect")] + return component_clone_via_reflect; + #[cfg(not(feature = "bevy_reflect"))] + return component_clone_ignore; + } + + /// Resolves the [`ComponentCloneBehavior`] to a [`ComponentCloneFn`]. If [`ComponentCloneBehavior::Default`] is + /// specified, the given `default` function will be used. + pub fn resolve(&self, default: ComponentCloneFn) -> ComponentCloneFn { + match self { + ComponentCloneBehavior::Default => default, + ComponentCloneBehavior::Ignore => component_clone_ignore, + ComponentCloneBehavior::Custom(custom) => *custom, + } + } +} + +/// Component [clone handler function](ComponentCloneFn) implemented using the [`Clone`] trait. +/// Can be [set](Component::clone_behavior) as clone handler for the specific component it is implemented for. +/// It will panic if set as handler for any other component. +/// +pub fn component_clone_via_clone( + source: &SourceComponent, + ctx: &mut ComponentCloneCtx, +) { + if let Some(component) = source.read::() { + ctx.write_target_component(component.clone()); + } +} + +/// Component [clone handler function](ComponentCloneFn) implemented using reflect. +/// Can be [set](Component::clone_behavior) as clone handler for any registered component, +/// but only reflected components will be cloned. +/// +/// To clone a component using this handler, the following must be true: +/// - World has [`AppTypeRegistry`](crate::reflect::AppTypeRegistry) +/// - Component has [`TypeId`](core::any::TypeId) +/// - Component is registered +/// - Component has [`ReflectFromPtr`](bevy_reflect::ReflectFromPtr) registered +/// - Component can be cloned via [`PartialReflect::reflect_clone`] _or_ has one of the following registered: [`ReflectFromReflect`](bevy_reflect::ReflectFromReflect), +/// [`ReflectDefault`](bevy_reflect::std_traits::ReflectDefault), [`ReflectFromWorld`](crate::reflect::ReflectFromWorld) +/// +/// If any of the conditions is not satisfied, the component will be skipped. +/// +/// See [`EntityClonerBuilder`](crate::entity::EntityClonerBuilder) for details. +/// +/// [`PartialReflect::reflect_clone`]: bevy_reflect::PartialReflect::reflect_clone +#[cfg(feature = "bevy_reflect")] +pub fn component_clone_via_reflect(source: &SourceComponent, ctx: &mut ComponentCloneCtx) { + let Some(app_registry) = ctx.type_registry().cloned() else { + return; + }; + let registry = app_registry.read(); + let Some(source_component_reflect) = source.read_reflect(®istry) else { + return; + }; + let component_info = ctx.component_info(); + // checked in read_source_component_reflect + let type_id = component_info.type_id().unwrap(); + + // Try to clone using `reflect_clone` + if let Ok(mut component) = source_component_reflect.reflect_clone() { + if let Some(reflect_component) = + registry.get_type_data::(type_id) + { + reflect_component.map_entities(&mut *component, ctx.entity_mapper()); + } + drop(registry); + + ctx.write_target_component_reflect(component); + return; + } + + // Try to clone using ReflectFromReflect + if let Some(reflect_from_reflect) = + registry.get_type_data::(type_id) + { + if let Some(mut component) = + reflect_from_reflect.from_reflect(source_component_reflect.as_partial_reflect()) + { + if let Some(reflect_component) = + registry.get_type_data::(type_id) + { + reflect_component.map_entities(&mut *component, ctx.entity_mapper()); + } + drop(registry); + + ctx.write_target_component_reflect(component); + return; + } + } + // Else, try to clone using ReflectDefault + if let Some(reflect_default) = + registry.get_type_data::(type_id) + { + let mut component = reflect_default.default(); + component.apply(source_component_reflect.as_partial_reflect()); + drop(registry); + ctx.write_target_component_reflect(component); + return; + } + // Otherwise, try to clone using ReflectFromWorld + if let Some(reflect_from_world) = + registry.get_type_data::(type_id) + { + use crate::{entity::EntityMapper, world::World}; + + let reflect_from_world = reflect_from_world.clone(); + let source_component_cloned = source_component_reflect.to_dynamic(); + let component_layout = component_info.layout(); + let target = ctx.target(); + let component_id = ctx.component_id(); + drop(registry); + ctx.queue_deferred(move |world: &mut World, mapper: &mut dyn EntityMapper| { + let mut component = reflect_from_world.from_world(world); + assert_eq!(type_id, (*component).type_id()); + component.apply(source_component_cloned.as_partial_reflect()); + if let Some(reflect_component) = app_registry + .read() + .get_type_data::(type_id) + { + reflect_component.map_entities(&mut *component, mapper); + } + // SAFETY: + // - component_id is from the same world as target entity + // - component is a valid value represented by component_id + unsafe { + use alloc::boxed::Box; + use bevy_ptr::OwningPtr; + + let raw_component_ptr = + core::ptr::NonNull::new_unchecked(Box::into_raw(component).cast::()); + world + .entity_mut(target) + .insert_by_id(component_id, OwningPtr::new(raw_component_ptr)); + + if component_layout.size() > 0 { + // Ensure we don't attempt to deallocate zero-sized components + alloc::alloc::dealloc(raw_component_ptr.as_ptr(), component_layout); + } + } + }); + } +} + +/// Noop implementation of component clone handler function. +/// +/// See [`EntityClonerBuilder`](crate::entity::EntityClonerBuilder) for details. +pub fn component_clone_ignore(_source: &SourceComponent, _ctx: &mut ComponentCloneCtx) {} + +/// Wrapper for components clone specialization using autoderef. +#[doc(hidden)] +pub struct DefaultCloneBehaviorSpecialization(PhantomData); + +impl Default for DefaultCloneBehaviorSpecialization { + fn default() -> Self { + Self(PhantomData) + } +} + +/// Base trait for components clone specialization using autoderef. +#[doc(hidden)] +pub trait DefaultCloneBehaviorBase { + fn default_clone_behavior(&self) -> ComponentCloneBehavior; +} + +impl DefaultCloneBehaviorBase for DefaultCloneBehaviorSpecialization { + fn default_clone_behavior(&self) -> ComponentCloneBehavior { + ComponentCloneBehavior::Default + } +} + +/// Specialized trait for components clone specialization using autoderef. +#[doc(hidden)] +pub trait DefaultCloneBehaviorViaClone { + fn default_clone_behavior(&self) -> ComponentCloneBehavior; +} + +impl DefaultCloneBehaviorViaClone for &DefaultCloneBehaviorSpecialization { + fn default_clone_behavior(&self) -> ComponentCloneBehavior { + ComponentCloneBehavior::clone::() + } +} diff --git a/crates/bevy_ecs/src/component/info.rs b/crates/bevy_ecs/src/component/info.rs new file mode 100644 index 0000000000..5a1bf96e16 --- /dev/null +++ b/crates/bevy_ecs/src/component/info.rs @@ -0,0 +1,721 @@ +use alloc::{borrow::Cow, vec::Vec}; +use bevy_platform::{collections::HashSet, sync::PoisonError}; +use bevy_ptr::OwningPtr; +#[cfg(feature = "bevy_reflect")] +use bevy_reflect::Reflect; +use bevy_utils::{prelude::DebugName, TypeIdMap}; +use core::{ + alloc::Layout, + any::{Any, TypeId}, + fmt::Debug, + mem::needs_drop, +}; + +use crate::{ + archetype::ArchetypeFlags, + component::{ + Component, ComponentCloneBehavior, ComponentMutability, QueuedComponents, + RequiredComponents, StorageType, + }, + lifecycle::ComponentHooks, + query::DebugCheckedUnwrap as _, + resource::Resource, + storage::SparseSetIndex, +}; + +/// Stores metadata for a type of component or resource stored in a specific [`World`](crate::world::World). +#[derive(Debug, Clone)] +pub struct ComponentInfo { + pub(super) id: ComponentId, + pub(super) descriptor: ComponentDescriptor, + pub(super) hooks: ComponentHooks, + pub(super) required_components: RequiredComponents, + pub(super) required_by: HashSet, +} + +impl ComponentInfo { + /// Returns a value uniquely identifying the current component. + #[inline] + pub fn id(&self) -> ComponentId { + self.id + } + + /// Returns the name of the current component. + #[inline] + pub fn name(&self) -> DebugName { + self.descriptor.name.clone() + } + + /// Returns `true` if the current component is mutable. + #[inline] + pub fn mutable(&self) -> bool { + self.descriptor.mutable + } + + /// Returns [`ComponentCloneBehavior`] of the current component. + #[inline] + pub fn clone_behavior(&self) -> &ComponentCloneBehavior { + &self.descriptor.clone_behavior + } + + /// Returns the [`TypeId`] of the underlying component type. + /// Returns `None` if the component does not correspond to a Rust type. + #[inline] + pub fn type_id(&self) -> Option { + self.descriptor.type_id + } + + /// Returns the layout used to store values of this component in memory. + #[inline] + pub fn layout(&self) -> Layout { + self.descriptor.layout + } + + #[inline] + /// Get the function which should be called to clean up values of + /// the underlying component type. This maps to the + /// [`Drop`] implementation for 'normal' Rust components + /// + /// Returns `None` if values of the underlying component type don't + /// need to be dropped, e.g. as reported by [`needs_drop`]. + pub fn drop(&self) -> Option)> { + self.descriptor.drop + } + + /// Returns a value indicating the storage strategy for the current component. + #[inline] + pub fn storage_type(&self) -> StorageType { + self.descriptor.storage_type + } + + /// Returns `true` if the underlying component type can be freely shared between threads. + /// If this returns `false`, then extra care must be taken to ensure that components + /// are not accessed from the wrong thread. + #[inline] + pub fn is_send_and_sync(&self) -> bool { + self.descriptor.is_send_and_sync + } + + /// Create a new [`ComponentInfo`]. + pub(crate) fn new(id: ComponentId, descriptor: ComponentDescriptor) -> Self { + ComponentInfo { + id, + descriptor, + hooks: Default::default(), + required_components: Default::default(), + required_by: Default::default(), + } + } + + /// Update the given flags to include any [`ComponentHook`](crate::component::ComponentHook) registered to self + #[inline] + pub(crate) fn update_archetype_flags(&self, flags: &mut ArchetypeFlags) { + if self.hooks().on_add.is_some() { + flags.insert(ArchetypeFlags::ON_ADD_HOOK); + } + if self.hooks().on_insert.is_some() { + flags.insert(ArchetypeFlags::ON_INSERT_HOOK); + } + if self.hooks().on_replace.is_some() { + flags.insert(ArchetypeFlags::ON_REPLACE_HOOK); + } + if self.hooks().on_remove.is_some() { + flags.insert(ArchetypeFlags::ON_REMOVE_HOOK); + } + if self.hooks().on_despawn.is_some() { + flags.insert(ArchetypeFlags::ON_DESPAWN_HOOK); + } + } + + /// Provides a reference to the collection of hooks associated with this [`Component`] + pub fn hooks(&self) -> &ComponentHooks { + &self.hooks + } + + /// Retrieves the [`RequiredComponents`] collection, which contains all required components (and their constructors) + /// needed by this component. This includes _recursive_ required components. + pub fn required_components(&self) -> &RequiredComponents { + &self.required_components + } +} + +/// A value which uniquely identifies the type of a [`Component`] or [`Resource`] within a +/// [`World`](crate::world::World). +/// +/// Each time a new `Component` type is registered within a `World` using +/// e.g. [`World::register_component`](crate::world::World::register_component) or +/// [`World::register_component_with_descriptor`](crate::world::World::register_component_with_descriptor) +/// or a Resource with e.g. [`World::init_resource`](crate::world::World::init_resource), +/// a corresponding `ComponentId` is created to track it. +/// +/// While the distinction between `ComponentId` and [`TypeId`] may seem superficial, breaking them +/// into two separate but related concepts allows components to exist outside of Rust's type system. +/// Each Rust type registered as a `Component` will have a corresponding `ComponentId`, but additional +/// `ComponentId`s may exist in a `World` to track components which cannot be +/// represented as Rust types for scripting or other advanced use-cases. +/// +/// A `ComponentId` is tightly coupled to its parent `World`. Attempting to use a `ComponentId` from +/// one `World` to access the metadata of a `Component` in a different `World` is undefined behavior +/// and must not be attempted. +/// +/// Given a type `T` which implements [`Component`], the `ComponentId` for `T` can be retrieved +/// from a `World` using [`World::component_id()`](crate::world::World::component_id) or via [`Components::component_id()`]. +/// Access to the `ComponentId` for a [`Resource`] is available via [`Components::resource_id()`]. +#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)] +#[cfg_attr( + feature = "bevy_reflect", + derive(Reflect), + reflect(Debug, Hash, PartialEq, Clone) +)] +pub struct ComponentId(pub(super) usize); + +impl ComponentId { + /// Creates a new [`ComponentId`]. + /// + /// The `index` is a unique value associated with each type of component in a given world. + /// Usually, this value is taken from a counter incremented for each type of component registered with the world. + #[inline] + pub const fn new(index: usize) -> ComponentId { + ComponentId(index) + } + + /// Returns the index of the current component. + #[inline] + pub fn index(self) -> usize { + self.0 + } +} + +impl SparseSetIndex for ComponentId { + #[inline] + fn sparse_set_index(&self) -> usize { + self.index() + } + + #[inline] + fn get_sparse_set_index(value: usize) -> Self { + Self(value) + } +} + +/// A value describing a component or resource, which may or may not correspond to a Rust type. +#[derive(Clone)] +pub struct ComponentDescriptor { + name: DebugName, + // SAFETY: This must remain private. It must match the statically known StorageType of the + // associated rust component type if one exists. + storage_type: StorageType, + // SAFETY: This must remain private. It must only be set to "true" if this component is + // actually Send + Sync + is_send_and_sync: bool, + type_id: Option, + layout: Layout, + // SAFETY: this function must be safe to call with pointers pointing to items of the type + // this descriptor describes. + // None if the underlying type doesn't need to be dropped + drop: Option unsafe fn(OwningPtr<'a>)>, + mutable: bool, + clone_behavior: ComponentCloneBehavior, +} + +// We need to ignore the `drop` field in our `Debug` impl +impl Debug for ComponentDescriptor { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("ComponentDescriptor") + .field("name", &self.name) + .field("storage_type", &self.storage_type) + .field("is_send_and_sync", &self.is_send_and_sync) + .field("type_id", &self.type_id) + .field("layout", &self.layout) + .field("mutable", &self.mutable) + .field("clone_behavior", &self.clone_behavior) + .finish() + } +} + +impl ComponentDescriptor { + /// # Safety + /// + /// `x` must point to a valid value of type `T`. + unsafe fn drop_ptr(x: OwningPtr<'_>) { + // SAFETY: Contract is required to be upheld by the caller. + unsafe { + x.drop_as::(); + } + } + + /// Create a new `ComponentDescriptor` for the type `T`. + pub fn new() -> Self { + Self { + name: DebugName::type_name::(), + storage_type: T::STORAGE_TYPE, + is_send_and_sync: true, + type_id: Some(TypeId::of::()), + layout: Layout::new::(), + drop: needs_drop::().then_some(Self::drop_ptr:: as _), + mutable: T::Mutability::MUTABLE, + clone_behavior: T::clone_behavior(), + } + } + + /// Create a new `ComponentDescriptor`. + /// + /// # Safety + /// - the `drop` fn must be usable on a pointer with a value of the layout `layout` + /// - the component type must be safe to access from any thread (Send + Sync in rust terms) + pub unsafe fn new_with_layout( + name: impl Into>, + storage_type: StorageType, + layout: Layout, + drop: Option unsafe fn(OwningPtr<'a>)>, + mutable: bool, + clone_behavior: ComponentCloneBehavior, + ) -> Self { + Self { + name: name.into().into(), + storage_type, + is_send_and_sync: true, + type_id: None, + layout, + drop, + mutable, + clone_behavior, + } + } + + /// Create a new `ComponentDescriptor` for a resource. + /// + /// The [`StorageType`] for resources is always [`StorageType::Table`]. + pub fn new_resource() -> Self { + Self { + name: DebugName::type_name::(), + // PERF: `SparseStorage` may actually be a more + // reasonable choice as `storage_type` for resources. + storage_type: StorageType::Table, + is_send_and_sync: true, + type_id: Some(TypeId::of::()), + layout: Layout::new::(), + drop: needs_drop::().then_some(Self::drop_ptr:: as _), + mutable: true, + clone_behavior: ComponentCloneBehavior::Default, + } + } + + pub(super) fn new_non_send(storage_type: StorageType) -> Self { + Self { + name: DebugName::type_name::(), + storage_type, + is_send_and_sync: false, + type_id: Some(TypeId::of::()), + layout: Layout::new::(), + drop: needs_drop::().then_some(Self::drop_ptr:: as _), + mutable: true, + clone_behavior: ComponentCloneBehavior::Default, + } + } + + /// Returns a value indicating the storage strategy for the current component. + #[inline] + pub fn storage_type(&self) -> StorageType { + self.storage_type + } + + /// Returns the [`TypeId`] of the underlying component type. + /// Returns `None` if the component does not correspond to a Rust type. + #[inline] + pub fn type_id(&self) -> Option { + self.type_id + } + + /// Returns the name of the current component. + #[inline] + pub fn name(&self) -> DebugName { + self.name.clone() + } + + /// Returns whether this component is mutable. + #[inline] + pub fn mutable(&self) -> bool { + self.mutable + } +} + +/// Stores metadata associated with each kind of [`Component`] in a given [`World`](crate::world::World). +#[derive(Debug, Default)] +pub struct Components { + pub(super) components: Vec>, + pub(super) indices: TypeIdMap, + pub(super) resource_indices: TypeIdMap, + // This is kept internal and local to verify that no deadlocks can occor. + pub(super) queued: bevy_platform::sync::RwLock, +} + +impl Components { + /// This registers any descriptor, component or resource. + /// + /// # Safety + /// + /// The id must have never been registered before. This must be a fresh registration. + #[inline] + pub(super) unsafe fn register_component_inner( + &mut self, + id: ComponentId, + descriptor: ComponentDescriptor, + ) { + let info = ComponentInfo::new(id, descriptor); + let least_len = id.0 + 1; + if self.components.len() < least_len { + self.components.resize_with(least_len, || None); + } + // SAFETY: We just extended the vec to make this index valid. + let slot = unsafe { self.components.get_mut(id.0).debug_checked_unwrap() }; + // Caller ensures id is unique + debug_assert!(slot.is_none()); + *slot = Some(info); + } + + /// Returns the number of components registered or queued with this instance. + #[inline] + pub fn len(&self) -> usize { + self.num_queued() + self.num_registered() + } + + /// Returns `true` if there are no components registered or queued with this instance. Otherwise, this returns `false`. + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns the number of components registered with this instance. + #[inline] + pub fn num_queued(&self) -> usize { + let queued = self.queued.read().unwrap_or_else(PoisonError::into_inner); + queued.components.len() + queued.dynamic_registrations.len() + queued.resources.len() + } + + /// Returns `true` if there are any components registered with this instance. Otherwise, this returns `false`. + #[inline] + pub fn any_queued(&self) -> bool { + self.num_queued() > 0 + } + + /// A faster version of [`Self::num_queued`]. + #[inline] + pub fn num_queued_mut(&mut self) -> usize { + let queued = self + .queued + .get_mut() + .unwrap_or_else(PoisonError::into_inner); + queued.components.len() + queued.dynamic_registrations.len() + queued.resources.len() + } + + /// A faster version of [`Self::any_queued`]. + #[inline] + pub fn any_queued_mut(&mut self) -> bool { + self.num_queued_mut() > 0 + } + + /// Returns the number of components registered with this instance. + #[inline] + pub fn num_registered(&self) -> usize { + self.components.len() + } + + /// Returns `true` if there are any components registered with this instance. Otherwise, this returns `false`. + #[inline] + pub fn any_registered(&self) -> bool { + self.num_registered() > 0 + } + + /// Gets the metadata associated with the given component, if it is registered. + /// This will return `None` if the id is not registered or is queued. + /// + /// This will return an incorrect result if `id` did not come from the same world as `self`. It may return `None` or a garbage value. + #[inline] + pub fn get_info(&self, id: ComponentId) -> Option<&ComponentInfo> { + self.components.get(id.0).and_then(|info| info.as_ref()) + } + + /// Gets the [`ComponentDescriptor`] of the component with this [`ComponentId`] if it is present. + /// This will return `None` only if the id is neither registered nor queued to be registered. + /// + /// Currently, the [`Cow`] will be [`Cow::Owned`] if and only if the component is queued. It will be [`Cow::Borrowed`] otherwise. + /// + /// This will return an incorrect result if `id` did not come from the same world as `self`. It may return `None` or a garbage value. + #[inline] + pub fn get_descriptor<'a>(&'a self, id: ComponentId) -> Option> { + self.components + .get(id.0) + .and_then(|info| info.as_ref().map(|info| Cow::Borrowed(&info.descriptor))) + .or_else(|| { + let queued = self.queued.read().unwrap_or_else(PoisonError::into_inner); + // first check components, then resources, then dynamic + queued + .components + .values() + .chain(queued.resources.values()) + .chain(queued.dynamic_registrations.iter()) + .find(|queued| queued.id == id) + .map(|queued| Cow::Owned(queued.descriptor.clone())) + }) + } + + /// Gets the name of the component with this [`ComponentId`] if it is present. + /// This will return `None` only if the id is neither registered nor queued to be registered. + /// + /// This will return an incorrect result if `id` did not come from the same world as `self`. It may return `None` or a garbage value. + #[inline] + pub fn get_name<'a>(&'a self, id: ComponentId) -> Option { + self.components + .get(id.0) + .and_then(|info| info.as_ref().map(|info| info.descriptor.name())) + .or_else(|| { + let queued = self.queued.read().unwrap_or_else(PoisonError::into_inner); + // first check components, then resources, then dynamic + queued + .components + .values() + .chain(queued.resources.values()) + .chain(queued.dynamic_registrations.iter()) + .find(|queued| queued.id == id) + .map(|queued| queued.descriptor.name.clone()) + }) + } + + /// Gets the metadata associated with the given component. + /// # Safety + /// + /// `id` must be a valid and fully registered [`ComponentId`]. + #[inline] + pub unsafe fn get_info_unchecked(&self, id: ComponentId) -> &ComponentInfo { + // SAFETY: The caller ensures `id` is valid. + unsafe { + self.components + .get(id.0) + .debug_checked_unwrap() + .as_ref() + .debug_checked_unwrap() + } + } + + #[inline] + pub(crate) fn get_hooks_mut(&mut self, id: ComponentId) -> Option<&mut ComponentHooks> { + self.components + .get_mut(id.0) + .and_then(|info| info.as_mut().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) + .and_then(|info| info.as_mut().map(|info| &mut info.required_components)) + } + + #[inline] + pub(crate) fn get_required_by(&self, id: ComponentId) -> Option<&HashSet> { + self.components + .get(id.0) + .and_then(|info| info.as_ref().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) + .and_then(|info| info.as_mut().map(|info| &mut info.required_by)) + } + + /// Returns true if the [`ComponentId`] is fully registered and valid. + /// Ids may be invalid if they are still queued to be registered. + /// Those ids are still correct, but they are not usable in every context yet. + #[inline] + pub fn is_id_valid(&self, id: ComponentId) -> bool { + self.components.get(id.0).is_some_and(Option::is_some) + } + + /// Type-erased equivalent of [`Components::valid_component_id()`]. + #[inline] + pub fn get_valid_id(&self, type_id: TypeId) -> Option { + self.indices.get(&type_id).copied() + } + + /// Returns the [`ComponentId`] of the given [`Component`] type `T` if it is fully registered. + /// If you want to include queued registration, see [`Components::component_id()`]. + /// + /// ``` + /// use bevy_ecs::prelude::*; + /// + /// let mut world = World::new(); + /// + /// #[derive(Component)] + /// struct ComponentA; + /// + /// let component_a_id = world.register_component::(); + /// + /// assert_eq!(component_a_id, world.components().valid_component_id::().unwrap()) + /// ``` + /// + /// # See also + /// + /// * [`Components::get_valid_id()`] + /// * [`Components::valid_resource_id()`] + /// * [`World::component_id()`](crate::world::World::component_id) + #[inline] + pub fn valid_component_id(&self) -> Option { + self.get_valid_id(TypeId::of::()) + } + + /// Type-erased equivalent of [`Components::valid_resource_id()`]. + #[inline] + pub fn get_valid_resource_id(&self, type_id: TypeId) -> Option { + self.resource_indices.get(&type_id).copied() + } + + /// Returns the [`ComponentId`] of the given [`Resource`] type `T` if it is fully registered. + /// If you want to include queued registration, see [`Components::resource_id()`]. + /// + /// ``` + /// use bevy_ecs::prelude::*; + /// + /// let mut world = World::new(); + /// + /// #[derive(Resource, Default)] + /// struct ResourceA; + /// + /// let resource_a_id = world.init_resource::(); + /// + /// assert_eq!(resource_a_id, world.components().valid_resource_id::().unwrap()) + /// ``` + /// + /// # See also + /// + /// * [`Components::valid_component_id()`] + /// * [`Components::get_resource_id()`] + #[inline] + pub fn valid_resource_id(&self) -> Option { + self.get_valid_resource_id(TypeId::of::()) + } + + /// Type-erased equivalent of [`Components::component_id()`]. + #[inline] + pub fn get_id(&self, type_id: TypeId) -> Option { + self.indices.get(&type_id).copied().or_else(|| { + self.queued + .read() + .unwrap_or_else(PoisonError::into_inner) + .components + .get(&type_id) + .map(|queued| queued.id) + }) + } + + /// Returns the [`ComponentId`] of the given [`Component`] type `T`. + /// + /// The returned `ComponentId` is specific to the `Components` instance + /// it was retrieved from and should not be used with another `Components` + /// instance. + /// + /// Returns [`None`] if the `Component` type has not yet been initialized using + /// [`ComponentsRegistrator::register_component()`](super::ComponentsRegistrator::register_component) or + /// [`ComponentsQueuedRegistrator::queue_register_component()`](super::ComponentsQueuedRegistrator::queue_register_component). + /// + /// ``` + /// use bevy_ecs::prelude::*; + /// + /// let mut world = World::new(); + /// + /// #[derive(Component)] + /// struct ComponentA; + /// + /// let component_a_id = world.register_component::(); + /// + /// assert_eq!(component_a_id, world.components().component_id::().unwrap()) + /// ``` + /// + /// # See also + /// + /// * [`Components::get_id()`] + /// * [`Components::resource_id()`] + /// * [`World::component_id()`](crate::world::World::component_id) + #[inline] + pub fn component_id(&self) -> Option { + self.get_id(TypeId::of::()) + } + + /// Type-erased equivalent of [`Components::resource_id()`]. + #[inline] + pub fn get_resource_id(&self, type_id: TypeId) -> Option { + self.resource_indices.get(&type_id).copied().or_else(|| { + self.queued + .read() + .unwrap_or_else(PoisonError::into_inner) + .resources + .get(&type_id) + .map(|queued| queued.id) + }) + } + + /// Returns the [`ComponentId`] of the given [`Resource`] type `T`. + /// + /// The returned `ComponentId` is specific to the `Components` instance + /// it was retrieved from and should not be used with another `Components` + /// instance. + /// + /// Returns [`None`] if the `Resource` type has not yet been initialized using + /// [`ComponentsRegistrator::register_resource()`](super::ComponentsRegistrator::register_resource) or + /// [`ComponentsQueuedRegistrator::queue_register_resource()`](super::ComponentsQueuedRegistrator::queue_register_resource). + /// + /// ``` + /// use bevy_ecs::prelude::*; + /// + /// let mut world = World::new(); + /// + /// #[derive(Resource, Default)] + /// struct ResourceA; + /// + /// let resource_a_id = world.init_resource::(); + /// + /// assert_eq!(resource_a_id, world.components().resource_id::().unwrap()) + /// ``` + /// + /// # See also + /// + /// * [`Components::component_id()`] + /// * [`Components::get_resource_id()`] + #[inline] + pub fn resource_id(&self) -> Option { + self.get_resource_id(TypeId::of::()) + } + + /// # Safety + /// + /// The [`ComponentDescriptor`] must match the [`TypeId`]. + /// The [`ComponentId`] must be unique. + /// The [`TypeId`] and [`ComponentId`] must not be registered or queued. + #[inline] + pub(super) unsafe fn register_resource_unchecked( + &mut self, + type_id: TypeId, + component_id: ComponentId, + descriptor: ComponentDescriptor, + ) { + // SAFETY: ensured by caller + unsafe { + self.register_component_inner(component_id, descriptor); + } + let prev = self.resource_indices.insert(type_id, component_id); + debug_assert!(prev.is_none()); + } + + /// Gets an iterator over all components fully registered with this instance. + pub fn iter_registered(&self) -> impl Iterator + '_ { + self.components.iter().filter_map(Option::as_ref) + } +} diff --git a/crates/bevy_ecs/src/component/mod.rs b/crates/bevy_ecs/src/component/mod.rs new file mode 100644 index 0000000000..8b57829243 --- /dev/null +++ b/crates/bevy_ecs/src/component/mod.rs @@ -0,0 +1,758 @@ +//! Types for declaring and storing [`Component`]s. + +mod clone; +mod info; +mod register; +mod required; +mod tick; + +pub use clone::*; +pub use info::*; +pub use register::*; +pub use required::*; +pub use tick::*; + +use crate::{ + entity::EntityMapper, + lifecycle::ComponentHook, + system::{Local, SystemParam}, + world::{FromWorld, World}, +}; +use alloc::vec::Vec; +pub use bevy_ecs_macros::Component; +use core::{fmt::Debug, marker::PhantomData, ops::Deref}; + +/// A data type that can be used to store data for an [entity]. +/// +/// `Component` is a [derivable trait]: this means that a data type can implement it by applying a `#[derive(Component)]` attribute to it. +/// However, components must always satisfy the `Send + Sync + 'static` trait bounds. +/// +/// [entity]: crate::entity +/// [derivable trait]: https://doc.rust-lang.org/book/appendix-03-derivable-traits.html +/// +/// # Examples +/// +/// Components can take many forms: they are usually structs, but can also be of every other kind of data type, like enums or zero sized types. +/// The following examples show how components are laid out in code. +/// +/// ``` +/// # use bevy_ecs::component::Component; +/// # struct Color; +/// # +/// // A component can contain data... +/// #[derive(Component)] +/// struct LicensePlate(String); +/// +/// // ... but it can also be a zero-sized marker. +/// #[derive(Component)] +/// struct Car; +/// +/// // Components can also be structs with named fields... +/// #[derive(Component)] +/// struct VehiclePerformance { +/// acceleration: f32, +/// top_speed: f32, +/// handling: f32, +/// } +/// +/// // ... or enums. +/// #[derive(Component)] +/// enum WheelCount { +/// Two, +/// Three, +/// Four, +/// } +/// ``` +/// +/// # Component and data access +/// +/// Components can be marked as immutable by adding the `#[component(immutable)]` +/// attribute when using the derive macro. +/// See the documentation for [`ComponentMutability`] for more details around this +/// feature. +/// +/// See the [`entity`] module level documentation to learn how to add or remove components from an entity. +/// +/// See the documentation for [`Query`] to learn how to access component data from a system. +/// +/// [`entity`]: crate::entity#usage +/// [`Query`]: crate::system::Query +/// [`ComponentMutability`]: crate::component::ComponentMutability +/// +/// # Choosing a storage type +/// +/// Components can be stored in the world using different strategies with their own performance implications. +/// By default, components are added to the [`Table`] storage, which is optimized for query iteration. +/// +/// Alternatively, components can be added to the [`SparseSet`] storage, which is optimized for component insertion and removal. +/// This is achieved by adding an additional `#[component(storage = "SparseSet")]` attribute to the derive one: +/// +/// ``` +/// # use bevy_ecs::component::Component; +/// # +/// #[derive(Component)] +/// #[component(storage = "SparseSet")] +/// struct ComponentA; +/// ``` +/// +/// [`Table`]: crate::storage::Table +/// [`SparseSet`]: crate::storage::SparseSet +/// +/// # Required Components +/// +/// Components can specify Required Components. If some [`Component`] `A` requires [`Component`] `B`, then when `A` is inserted, +/// `B` will _also_ be initialized and inserted (if it was not manually specified). +/// +/// The [`Default`] constructor will be used to initialize the component, by default: +/// +/// ``` +/// # use bevy_ecs::prelude::*; +/// #[derive(Component)] +/// #[require(B)] +/// struct A; +/// +/// #[derive(Component, Default, PartialEq, Eq, Debug)] +/// struct B(usize); +/// +/// # let mut world = World::default(); +/// // This will implicitly also insert B with the Default constructor +/// let id = world.spawn(A).id(); +/// assert_eq!(&B(0), world.entity(id).get::().unwrap()); +/// +/// // This will _not_ implicitly insert B, because it was already provided +/// world.spawn((A, B(11))); +/// ``` +/// +/// Components can have more than one required component: +/// +/// ``` +/// # use bevy_ecs::prelude::*; +/// #[derive(Component)] +/// #[require(B, C)] +/// struct A; +/// +/// #[derive(Component, Default, PartialEq, Eq, Debug)] +/// #[require(C)] +/// struct B(usize); +/// +/// #[derive(Component, Default, PartialEq, Eq, Debug)] +/// struct C(u32); +/// +/// # let mut world = World::default(); +/// // 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()); +/// ``` +/// +/// You can define inline component values that take the following forms: +/// ``` +/// # use bevy_ecs::prelude::*; +/// #[derive(Component)] +/// #[require( +/// B(1), // tuple structs +/// C { // named-field structs +/// x: 1, +/// ..Default::default() +/// }, +/// D::One, // enum variants +/// E::ONE, // associated consts +/// F::new(1) // constructors +/// )] +/// struct A; +/// +/// #[derive(Component, PartialEq, Eq, Debug)] +/// struct B(u8); +/// +/// #[derive(Component, PartialEq, Eq, Debug, Default)] +/// struct C { +/// x: u8, +/// y: u8, +/// } +/// +/// #[derive(Component, PartialEq, Eq, Debug)] +/// enum D { +/// Zero, +/// One, +/// } +/// +/// #[derive(Component, PartialEq, Eq, Debug)] +/// struct E(u8); +/// +/// impl E { +/// pub const ONE: Self = Self(1); +/// } +/// +/// #[derive(Component, PartialEq, Eq, Debug)] +/// struct F(u8); +/// +/// impl F { +/// fn new(value: u8) -> Self { +/// Self(value) +/// } +/// } +/// +/// # let mut world = World::default(); +/// let id = world.spawn(A).id(); +/// assert_eq!(&B(1), world.entity(id).get::().unwrap()); +/// assert_eq!(&C { x: 1, y: 0 }, world.entity(id).get::().unwrap()); +/// assert_eq!(&D::One, world.entity(id).get::().unwrap()); +/// assert_eq!(&E(1), world.entity(id).get::().unwrap()); +/// assert_eq!(&F(1), world.entity(id).get::().unwrap()); +/// ```` +/// +/// +/// You can also define arbitrary expressions by using `=` +/// +/// ``` +/// # use bevy_ecs::prelude::*; +/// #[derive(Component)] +/// #[require(C = init_c())] +/// struct A; +/// +/// #[derive(Component, PartialEq, Eq, Debug)] +/// #[require(C = C(20))] +/// struct B; +/// +/// #[derive(Component, PartialEq, Eq, Debug)] +/// struct C(usize); +/// +/// fn init_c() -> C { +/// C(10) +/// } +/// +/// # let mut world = World::default(); +/// // This will implicitly also insert C with the init_c() constructor +/// let id = world.spawn(A).id(); +/// assert_eq!(&C(10), world.entity(id).get::().unwrap()); +/// +/// // This will implicitly also insert C with the `|| C(20)` constructor closure +/// let id = world.spawn(B).id(); +/// assert_eq!(&C(20), world.entity(id).get::().unwrap()); +/// ``` +/// +/// Required components are _recursive_. This means, if a Required Component has required components, +/// those components will _also_ be inserted if they are missing: +/// +/// ``` +/// # use bevy_ecs::prelude::*; +/// #[derive(Component)] +/// #[require(B)] +/// struct A; +/// +/// #[derive(Component, Default, PartialEq, Eq, Debug)] +/// #[require(C)] +/// struct B(usize); +/// +/// #[derive(Component, Default, PartialEq, Eq, Debug)] +/// struct C(u32); +/// +/// # let mut world = World::default(); +/// // 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()); +/// ``` +/// +/// Note that cycles in the "component require tree" will result in stack overflows when attempting to +/// insert a component. +/// +/// This "multiple inheritance" pattern does mean that it is possible to have duplicate requires for a given type +/// at different levels of the inheritance tree: +/// +/// ``` +/// # use bevy_ecs::prelude::*; +/// #[derive(Component)] +/// struct X(usize); +/// +/// #[derive(Component, Default)] +/// #[require(X(1))] +/// struct Y; +/// +/// #[derive(Component)] +/// #[require( +/// Y, +/// X(2), +/// )] +/// struct Z; +/// +/// # let mut world = World::default(); +/// // In this case, the x2 constructor is used for X +/// let id = world.spawn(Z).id(); +/// assert_eq!(2, world.entity(id).get::().unwrap().0); +/// ``` +/// +/// In general, this shouldn't happen often, but when it does the algorithm for choosing the constructor from the tree is simple and predictable: +/// 1. A constructor from a direct `#[require()]`, if one exists, is selected with priority. +/// 2. Otherwise, perform a Depth First Search on the tree of requirements and select the first one found. +/// +/// From a user perspective, just think about this as the following: +/// 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. +/// +/// # Relationships between Entities +/// +/// Sometimes it is useful to define relationships between entities. A common example is the +/// parent / child relationship. Since Components are how data is stored for Entities, one might +/// naturally think to create a Component which has a field of type [`Entity`]. +/// +/// To facilitate this pattern, Bevy provides the [`Relationship`](`crate::relationship::Relationship`) +/// trait. You can derive the [`Relationship`](`crate::relationship::Relationship`) and +/// [`RelationshipTarget`](`crate::relationship::RelationshipTarget`) traits in addition to the +/// Component trait in order to implement data driven relationships between entities, see the trait +/// docs for more details. +/// +/// In addition, Bevy provides canonical implementations of the parent / child relationship via the +/// [`ChildOf`](crate::hierarchy::ChildOf) [`Relationship`](crate::relationship::Relationship) and +/// the [`Children`](crate::hierarchy::Children) +/// [`RelationshipTarget`](crate::relationship::RelationshipTarget). +/// +/// # Adding component's hooks +/// +/// See [`ComponentHooks`] for a detailed explanation of component's hooks. +/// +/// Alternatively to the example shown in [`ComponentHooks`]' documentation, hooks can be configured using following attributes: +/// - `#[component(on_add = on_add_function)]` +/// - `#[component(on_insert = on_insert_function)]` +/// - `#[component(on_replace = on_replace_function)]` +/// - `#[component(on_remove = on_remove_function)]` +/// +/// ``` +/// # use bevy_ecs::component::Component; +/// # use bevy_ecs::lifecycle::HookContext; +/// # use bevy_ecs::world::DeferredWorld; +/// # use bevy_ecs::entity::Entity; +/// # use bevy_ecs::component::ComponentId; +/// # use core::panic::Location; +/// # +/// #[derive(Component)] +/// #[component(on_add = my_on_add_hook)] +/// #[component(on_insert = my_on_insert_hook)] +/// // Another possible way of configuring hooks: +/// // #[component(on_add = my_on_add_hook, on_insert = my_on_insert_hook)] +/// // +/// // We don't have a replace or remove hook, so we can leave them out: +/// // #[component(on_replace = my_on_replace_hook, on_remove = my_on_remove_hook)] +/// struct ComponentA; +/// +/// fn my_on_add_hook(world: DeferredWorld, context: HookContext) { +/// // ... +/// } +/// +/// // You can also destructure items directly in the signature +/// fn my_on_insert_hook(world: DeferredWorld, HookContext { caller, .. }: HookContext) { +/// // ... +/// } +/// ``` +/// +/// This also supports function calls that yield closures +/// +/// ``` +/// # use bevy_ecs::component::Component; +/// # use bevy_ecs::lifecycle::HookContext; +/// # use bevy_ecs::world::DeferredWorld; +/// # +/// #[derive(Component)] +/// #[component(on_add = my_msg_hook("hello"))] +/// #[component(on_despawn = my_msg_hook("yoink"))] +/// struct ComponentA; +/// +/// // a hook closure generating function +/// fn my_msg_hook(message: &'static str) -> impl Fn(DeferredWorld, HookContext) { +/// move |_world, _ctx| { +/// println!("{message}"); +/// } +/// } +/// +/// ``` +/// # Setting the clone behavior +/// +/// You can specify how the [`Component`] is cloned when deriving it. +/// +/// Your options are the functions and variants of [`ComponentCloneBehavior`] +/// See [Handlers section of `EntityClonerBuilder`](crate::entity::EntityClonerBuilder#handlers) to understand how this affects handler priority. +/// ``` +/// # use bevy_ecs::prelude::*; +/// +/// #[derive(Component)] +/// #[component(clone_behavior = Ignore)] +/// struct MyComponent; +/// +/// ``` +/// +/// # Implementing the trait for foreign types +/// +/// As a consequence of the [orphan rule], it is not possible to separate into two different crates the implementation of `Component` from the definition of a type. +/// This means that it is not possible to directly have a type defined in a third party library as a component. +/// This important limitation can be easily worked around using the [newtype pattern]: +/// this makes it possible to locally define and implement `Component` for a tuple struct that wraps the foreign type. +/// The following example gives a demonstration of this pattern. +/// +/// ``` +/// // `Component` is defined in the `bevy_ecs` crate. +/// use bevy_ecs::component::Component; +/// +/// // `Duration` is defined in the `std` crate. +/// use std::time::Duration; +/// +/// // It is not possible to implement `Component` for `Duration` from this position, as they are +/// // both foreign items, defined in an external crate. However, nothing prevents to define a new +/// // `Cooldown` type that wraps `Duration`. As `Cooldown` is defined in a local crate, it is +/// // possible to implement `Component` for it. +/// #[derive(Component)] +/// struct Cooldown(Duration); +/// ``` +/// +/// [orphan rule]: https://doc.rust-lang.org/book/ch10-02-traits.html#implementing-a-trait-on-a-type +/// [newtype pattern]: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#using-the-newtype-pattern-to-implement-external-traits-on-external-types +/// +/// # `!Sync` Components +/// A `!Sync` type cannot implement `Component`. However, it is possible to wrap a `Send` but not `Sync` +/// type in [`SyncCell`] or the currently unstable [`Exclusive`] to make it `Sync`. This forces only +/// having mutable access (`&mut T` only, never `&T`), but makes it safe to reference across multiple +/// threads. +/// +/// This will fail to compile since `RefCell` is `!Sync`. +/// ```compile_fail +/// # use std::cell::RefCell; +/// # use bevy_ecs::component::Component; +/// #[derive(Component)] +/// struct NotSync { +/// counter: RefCell, +/// } +/// ``` +/// +/// This will compile since the `RefCell` is wrapped with `SyncCell`. +/// ``` +/// # use std::cell::RefCell; +/// # use bevy_ecs::component::Component; +/// use bevy_platform::cell::SyncCell; +/// +/// // This will compile. +/// #[derive(Component)] +/// struct ActuallySync { +/// counter: SyncCell>, +/// } +/// ``` +/// +/// [`SyncCell`]: bevy_platform::cell::SyncCell +/// [`Exclusive`]: https://doc.rust-lang.org/nightly/std/sync/struct.Exclusive.html +/// [`ComponentHooks`]: crate::lifecycle::ComponentHooks +#[diagnostic::on_unimplemented( + message = "`{Self}` is not a `Component`", + label = "invalid `Component`", + note = "consider annotating `{Self}` with `#[derive(Component)]`" +)] +pub trait Component: Send + Sync + 'static { + /// A constant indicating the storage type used for this component. + const STORAGE_TYPE: StorageType; + + /// A marker type to assist Bevy with determining if this component is + /// mutable, or immutable. Mutable components will have [`Component`], + /// while immutable components will instead have [`Component`]. + /// + /// * For a component to be mutable, this type must be [`Mutable`]. + /// * For a component to be immutable, this type must be [`Immutable`]. + type Mutability: ComponentMutability; + + /// Gets the `on_add` [`ComponentHook`] for this [`Component`] if one is defined. + fn on_add() -> Option { + None + } + + /// Gets the `on_insert` [`ComponentHook`] for this [`Component`] if one is defined. + fn on_insert() -> Option { + None + } + + /// Gets the `on_replace` [`ComponentHook`] for this [`Component`] if one is defined. + fn on_replace() -> Option { + None + } + + /// Gets the `on_remove` [`ComponentHook`] for this [`Component`] if one is defined. + fn on_remove() -> Option { + None + } + + /// Gets the `on_despawn` [`ComponentHook`] for this [`Component`] if one is defined. + fn on_despawn() -> Option { + None + } + + /// Registers required components. + fn register_required_components( + _component_id: ComponentId, + _components: &mut ComponentsRegistrator, + _required_components: &mut RequiredComponents, + _inheritance_depth: u16, + _recursion_check_stack: &mut Vec, + ) { + } + + /// Called when registering this component, allowing to override clone function (or disable cloning altogether) for this component. + /// + /// See [Handlers section of `EntityClonerBuilder`](crate::entity::EntityClonerBuilder#handlers) to understand how this affects handler priority. + #[inline] + fn clone_behavior() -> ComponentCloneBehavior { + ComponentCloneBehavior::Default + } + + /// Maps the entities on this component using the given [`EntityMapper`]. This is used to remap entities in contexts like scenes and entity cloning. + /// When deriving [`Component`], this is populated by annotating fields containing entities with `#[entities]` + /// + /// ``` + /// # use bevy_ecs::{component::Component, entity::Entity}; + /// #[derive(Component)] + /// struct Inventory { + /// #[entities] + /// items: Vec + /// } + /// ``` + /// + /// Fields with `#[entities]` must implement [`MapEntities`](crate::entity::MapEntities). + /// + /// Bevy provides various implementations of [`MapEntities`](crate::entity::MapEntities), so that arbitrary combinations like these are supported with `#[entities]`: + /// + /// ```rust + /// # use bevy_ecs::{component::Component, entity::Entity}; + /// #[derive(Component)] + /// struct Inventory { + /// #[entities] + /// items: Vec> + /// } + /// ``` + /// + /// You might need more specialized logic. A likely cause of this is your component contains collections of entities that + /// don't implement [`MapEntities`](crate::entity::MapEntities). In that case, you can annotate your component with + /// `#[component(map_entities)]`. Using this attribute, you must implement `MapEntities` for the + /// component itself, and this method will simply call that implementation. + /// + /// ``` + /// # use bevy_ecs::{component::Component, entity::{Entity, MapEntities, EntityMapper}}; + /// # use std::collections::HashMap; + /// #[derive(Component)] + /// #[component(map_entities)] + /// struct Inventory { + /// items: HashMap + /// } + /// + /// impl MapEntities for Inventory { + /// fn map_entities(&mut self, entity_mapper: &mut M) { + /// self.items = self.items + /// .drain() + /// .map(|(id, count)|(entity_mapper.get_mapped(id), count)) + /// .collect(); + /// } + /// } + /// # let a = Entity::from_bits(0x1_0000_0001); + /// # let b = Entity::from_bits(0x1_0000_0002); + /// # let mut inv = Inventory { items: Default::default() }; + /// # inv.items.insert(a, 10); + /// # ::map_entities(&mut inv, &mut (a,b)); + /// # assert_eq!(inv.items.get(&b), Some(&10)); + /// ```` + /// + /// Alternatively, you can specify the path to a function with `#[component(map_entities = function_path)]`, similar to component hooks. + /// In this case, the inputs of the function should mirror the inputs to this method, with the second parameter being generic. + /// + /// ``` + /// # use bevy_ecs::{component::Component, entity::{Entity, MapEntities, EntityMapper}}; + /// # use std::collections::HashMap; + /// #[derive(Component)] + /// #[component(map_entities = map_the_map)] + /// // Also works: map_the_map:: or map_the_map::<_> + /// struct Inventory { + /// items: HashMap + /// } + /// + /// fn map_the_map(inv: &mut Inventory, entity_mapper: &mut M) { + /// inv.items = inv.items + /// .drain() + /// .map(|(id, count)|(entity_mapper.get_mapped(id), count)) + /// .collect(); + /// } + /// # let a = Entity::from_bits(0x1_0000_0001); + /// # let b = Entity::from_bits(0x1_0000_0002); + /// # let mut inv = Inventory { items: Default::default() }; + /// # inv.items.insert(a, 10); + /// # ::map_entities(&mut inv, &mut (a,b)); + /// # assert_eq!(inv.items.get(&b), Some(&10)); + /// ```` + /// + /// You can use the turbofish (`::`) to specify parameters when a function is generic, using either M or _ for the type of the mapper parameter. + #[inline] + fn map_entities(_this: &mut Self, _mapper: &mut E) {} +} + +mod private { + pub trait Seal {} +} + +/// The mutability option for a [`Component`]. This can either be: +/// * [`Mutable`] +/// * [`Immutable`] +/// +/// This is controlled through either [`Component::Mutability`] or `#[component(immutable)]` +/// when using the derive macro. +/// +/// Immutable components are guaranteed to never have an exclusive reference, +/// `&mut ...`, created while inserted onto an entity. +/// In all other ways, they are identical to mutable components. +/// This restriction allows hooks to observe all changes made to an immutable +/// component, effectively turning the `Insert` and `Replace` hooks into a +/// `OnMutate` hook. +/// This is not practical for mutable components, as the runtime cost of invoking +/// a hook for every exclusive reference created would be far too high. +/// +/// # Examples +/// +/// ```rust +/// # use bevy_ecs::component::Component; +/// # +/// #[derive(Component)] +/// #[component(immutable)] +/// struct ImmutableFoo; +/// ``` +pub trait ComponentMutability: private::Seal + 'static { + /// Boolean to indicate if this mutability setting implies a mutable or immutable + /// component. + const MUTABLE: bool; +} + +/// Parameter indicating a [`Component`] is immutable. +/// +/// See [`ComponentMutability`] for details. +pub struct Immutable; + +impl private::Seal for Immutable {} + +impl ComponentMutability for Immutable { + const MUTABLE: bool = false; +} + +/// Parameter indicating a [`Component`] is mutable. +/// +/// See [`ComponentMutability`] for details. +pub struct Mutable; + +impl private::Seal for Mutable {} + +impl ComponentMutability for Mutable { + const MUTABLE: bool = true; +} + +/// The storage used for a specific component type. +/// +/// # Examples +/// The [`StorageType`] for a component is configured via the derive attribute +/// +/// ``` +/// # use bevy_ecs::{prelude::*, component::*}; +/// #[derive(Component)] +/// #[component(storage = "SparseSet")] +/// struct A; +/// ``` +#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)] +pub enum StorageType { + /// Provides fast and cache-friendly iteration, but slower addition and removal of components. + /// This is the default storage type. + #[default] + Table, + /// Provides fast addition and removal of components, but slower iteration. + SparseSet, +} + +/// A [`SystemParam`] that provides access to the [`ComponentId`] for a specific component type. +/// +/// # Example +/// ``` +/// # use bevy_ecs::{system::Local, component::{Component, ComponentId, ComponentIdFor}}; +/// #[derive(Component)] +/// struct Player; +/// fn my_system(component_id: ComponentIdFor) { +/// let component_id: ComponentId = component_id.get(); +/// // ... +/// } +/// ``` +#[derive(SystemParam)] +pub struct ComponentIdFor<'s, T: Component>(Local<'s, InitComponentId>); + +impl ComponentIdFor<'_, T> { + /// Gets the [`ComponentId`] for the type `T`. + #[inline] + pub fn get(&self) -> ComponentId { + **self + } +} + +impl Deref for ComponentIdFor<'_, T> { + type Target = ComponentId; + fn deref(&self) -> &Self::Target { + &self.0.component_id + } +} + +impl From> for ComponentId { + #[inline] + fn from(to_component_id: ComponentIdFor) -> ComponentId { + *to_component_id + } +} + +/// Initializes the [`ComponentId`] for a specific type when used with [`FromWorld`]. +struct InitComponentId { + component_id: ComponentId, + marker: PhantomData, +} + +impl FromWorld for InitComponentId { + fn from_world(world: &mut World) -> Self { + Self { + component_id: world.register_component::(), + marker: PhantomData, + } + } +} diff --git a/crates/bevy_ecs/src/component/register.rs b/crates/bevy_ecs/src/component/register.rs new file mode 100644 index 0000000000..bf1720b005 --- /dev/null +++ b/crates/bevy_ecs/src/component/register.rs @@ -0,0 +1,679 @@ +use alloc::{boxed::Box, vec::Vec}; +use bevy_platform::sync::PoisonError; +use bevy_utils::TypeIdMap; +use core::any::Any; +use core::ops::DerefMut; +use core::{any::TypeId, fmt::Debug, ops::Deref}; + +use crate::query::DebugCheckedUnwrap as _; +use crate::{ + component::{ + Component, ComponentDescriptor, ComponentId, Components, RequiredComponents, StorageType, + }, + resource::Resource, +}; + +/// Generates [`ComponentId`]s. +#[derive(Debug, Default)] +pub struct ComponentIds { + next: bevy_platform::sync::atomic::AtomicUsize, +} + +impl ComponentIds { + /// Peeks the next [`ComponentId`] to be generated without generating it. + pub fn peek(&self) -> ComponentId { + ComponentId( + self.next + .load(bevy_platform::sync::atomic::Ordering::Relaxed), + ) + } + + /// Generates and returns the next [`ComponentId`]. + pub fn next(&self) -> ComponentId { + ComponentId( + self.next + .fetch_add(1, bevy_platform::sync::atomic::Ordering::Relaxed), + ) + } + + /// Peeks the next [`ComponentId`] to be generated without generating it. + pub fn peek_mut(&mut self) -> ComponentId { + ComponentId(*self.next.get_mut()) + } + + /// Generates and returns the next [`ComponentId`]. + pub fn next_mut(&mut self) -> ComponentId { + let id = self.next.get_mut(); + let result = ComponentId(*id); + *id += 1; + result + } + + /// Returns the number of [`ComponentId`]s generated. + pub fn len(&self) -> usize { + self.peek().0 + } + + /// Returns true if and only if no ids have been generated. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } +} + +/// A [`Components`] wrapper that enables additional features, like registration. +pub struct ComponentsRegistrator<'w> { + components: &'w mut Components, + ids: &'w mut ComponentIds, +} + +impl Deref for ComponentsRegistrator<'_> { + type Target = Components; + + fn deref(&self) -> &Self::Target { + self.components + } +} + +impl DerefMut for ComponentsRegistrator<'_> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.components + } +} + +impl<'w> ComponentsRegistrator<'w> { + /// Constructs a new [`ComponentsRegistrator`]. + /// + /// # Safety + /// + /// The [`Components`] and [`ComponentIds`] must match. + /// For example, they must be from the same world. + pub unsafe fn new(components: &'w mut Components, ids: &'w mut ComponentIds) -> Self { + Self { components, ids } + } + + /// Converts this [`ComponentsRegistrator`] into a [`ComponentsQueuedRegistrator`]. + /// This is intended for use to pass this value to a function that requires [`ComponentsQueuedRegistrator`]. + /// It is generally not a good idea to queue a registration when you can instead register directly on this type. + pub fn as_queued(&self) -> ComponentsQueuedRegistrator<'_> { + // SAFETY: ensured by the caller that created self. + unsafe { ComponentsQueuedRegistrator::new(self.components, self.ids) } + } + + /// Applies every queued registration. + /// This ensures that every valid [`ComponentId`] is registered, + /// enabling retrieving [`ComponentInfo`](super::ComponentInfo), etc. + pub fn apply_queued_registrations(&mut self) { + if !self.any_queued_mut() { + return; + } + + // Note: + // + // This is not just draining the queue. We need to empty the queue without removing the information from `Components`. + // If we drained directly, we could break invariance. + // + // For example, say `ComponentA` and `ComponentB` are queued, and `ComponentA` requires `ComponentB`. + // If we drain directly, and `ComponentA` was the first to be registered, then, when `ComponentA` + // registers `ComponentB` in `Component::register_required_components`, + // `Components` will not know that `ComponentB` was queued + // (since it will have been drained from the queue.) + // If that happened, `Components` would assign a new `ComponentId` to `ComponentB` + // which would be *different* than the id it was assigned in the queue. + // Then, when the drain iterator gets to `ComponentB`, + // it would be unsafely registering `ComponentB`, which is already registered. + // + // As a result, we need to pop from each queue one by one instead of draining. + + // components + while let Some(registrator) = { + let queued = self + .components + .queued + .get_mut() + .unwrap_or_else(PoisonError::into_inner); + queued.components.keys().next().copied().map(|type_id| { + // SAFETY: the id just came from a valid iterator. + unsafe { queued.components.remove(&type_id).debug_checked_unwrap() } + }) + } { + registrator.register(self); + } + + // resources + while let Some(registrator) = { + let queued = self + .components + .queued + .get_mut() + .unwrap_or_else(PoisonError::into_inner); + queued.resources.keys().next().copied().map(|type_id| { + // SAFETY: the id just came from a valid iterator. + unsafe { queued.resources.remove(&type_id).debug_checked_unwrap() } + }) + } { + registrator.register(self); + } + + // dynamic + let queued = &mut self + .components + .queued + .get_mut() + .unwrap_or_else(PoisonError::into_inner); + if !queued.dynamic_registrations.is_empty() { + for registrator in core::mem::take(&mut queued.dynamic_registrations) { + registrator.register(self); + } + } + } + + /// Registers a [`Component`] of type `T` with this instance. + /// If a component of this type has already been registered, this will return + /// the ID of the pre-existing component. + /// + /// # See also + /// + /// * [`Components::component_id()`] + /// * [`ComponentsRegistrator::register_component_with_descriptor()`] + #[inline] + pub fn register_component(&mut self) -> ComponentId { + self.register_component_checked::(&mut Vec::new()) + } + + /// Same as [`Self::register_component_unchecked`] but keeps a checks for safety. + #[inline] + pub(super) fn register_component_checked( + &mut self, + recursion_check_stack: &mut Vec, + ) -> ComponentId { + let type_id = TypeId::of::(); + if let Some(id) = self.indices.get(&type_id) { + return *id; + } + + if let Some(registrator) = self + .components + .queued + .get_mut() + .unwrap_or_else(PoisonError::into_inner) + .components + .remove(&type_id) + { + // If we are trying to register something that has already been queued, we respect the queue. + // Just like if we are trying to register something that already is, we respect the first registration. + return registrator.register(self); + } + + let id = self.ids.next_mut(); + // SAFETY: The component is not currently registered, and the id is fresh. + unsafe { + self.register_component_unchecked::(recursion_check_stack, id); + } + id + } + + /// # Safety + /// + /// Neither this component, nor its id may be registered or queued. This must be a new registration. + #[inline] + unsafe fn register_component_unchecked( + &mut self, + recursion_check_stack: &mut Vec, + id: ComponentId, + ) { + // SAFETY: ensured by caller. + unsafe { + self.register_component_inner(id, ComponentDescriptor::new::()); + } + let type_id = TypeId::of::(); + let prev = self.indices.insert(type_id, id); + debug_assert!(prev.is_none()); + + let mut required_components = RequiredComponents::default(); + T::register_required_components( + id, + self, + &mut required_components, + 0, + recursion_check_stack, + ); + // SAFETY: we just inserted it in `register_component_inner` + let info = unsafe { + &mut self + .components + .components + .get_mut(id.0) + .debug_checked_unwrap() + .as_mut() + .debug_checked_unwrap() + }; + + info.hooks.update_from_component::(); + + info.required_components = required_components; + } + + /// Registers a component described by `descriptor`. + /// + /// # Note + /// + /// If this method is called multiple times with identical descriptors, a distinct [`ComponentId`] + /// will be created for each one. + /// + /// # See also + /// + /// * [`Components::component_id()`] + /// * [`ComponentsRegistrator::register_component()`] + #[inline] + pub fn register_component_with_descriptor( + &mut self, + descriptor: ComponentDescriptor, + ) -> ComponentId { + let id = self.ids.next_mut(); + // SAFETY: The id is fresh. + unsafe { + self.register_component_inner(id, descriptor); + } + id + } + + /// 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. + /// + /// # See also + /// + /// * [`Components::resource_id()`] + /// * [`ComponentsRegistrator::register_resource_with_descriptor()`] + #[inline] + pub fn register_resource(&mut self) -> ComponentId { + // SAFETY: The [`ComponentDescriptor`] matches the [`TypeId`] + unsafe { + self.register_resource_with(TypeId::of::(), || { + ComponentDescriptor::new_resource::() + }) + } + } + + /// Registers a [non-send resource](crate::system::NonSend) 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. + #[inline] + pub fn register_non_send(&mut self) -> ComponentId { + // SAFETY: The [`ComponentDescriptor`] matches the [`TypeId`] + unsafe { + self.register_resource_with(TypeId::of::(), || { + ComponentDescriptor::new_non_send::(StorageType::default()) + }) + } + } + + /// Same as [`Components::register_resource_unchecked`] but handles safety. + /// + /// # Safety + /// + /// The [`ComponentDescriptor`] must match the [`TypeId`]. + #[inline] + unsafe fn register_resource_with( + &mut self, + type_id: TypeId, + descriptor: impl FnOnce() -> ComponentDescriptor, + ) -> ComponentId { + if let Some(id) = self.resource_indices.get(&type_id) { + return *id; + } + + if let Some(registrator) = self + .components + .queued + .get_mut() + .unwrap_or_else(PoisonError::into_inner) + .resources + .remove(&type_id) + { + // If we are trying to register something that has already been queued, we respect the queue. + // Just like if we are trying to register something that already is, we respect the first registration. + return registrator.register(self); + } + + let id = self.ids.next_mut(); + // SAFETY: The resource is not currently registered, the id is fresh, and the [`ComponentDescriptor`] matches the [`TypeId`] + unsafe { + self.register_resource_unchecked(type_id, id, descriptor()); + } + id + } + + /// Registers a [`Resource`] described by `descriptor`. + /// + /// # Note + /// + /// If this method is called multiple times with identical descriptors, a distinct [`ComponentId`] + /// will be created for each one. + /// + /// # See also + /// + /// * [`Components::resource_id()`] + /// * [`ComponentsRegistrator::register_resource()`] + #[inline] + pub fn register_resource_with_descriptor( + &mut self, + descriptor: ComponentDescriptor, + ) -> ComponentId { + let id = self.ids.next_mut(); + // SAFETY: The id is fresh. + unsafe { + self.register_component_inner(id, descriptor); + } + id + } +} + +/// A queued component registration. +pub(super) struct QueuedRegistration { + pub(super) registrator: + Box, + pub(super) id: ComponentId, + pub(super) descriptor: ComponentDescriptor, +} + +impl QueuedRegistration { + /// Creates the [`QueuedRegistration`]. + /// + /// # Safety + /// + /// [`ComponentId`] must be unique. + unsafe fn new( + id: ComponentId, + descriptor: ComponentDescriptor, + func: impl FnOnce(&mut ComponentsRegistrator, ComponentId, ComponentDescriptor) + 'static, + ) -> Self { + Self { + registrator: Box::new(func), + id, + descriptor, + } + } + + /// Performs the registration, returning the now valid [`ComponentId`]. + pub(super) fn register(self, registrator: &mut ComponentsRegistrator) -> ComponentId { + (self.registrator)(registrator, self.id, self.descriptor); + self.id + } +} + +/// Allows queuing components to be registered. +#[derive(Default)] +pub struct QueuedComponents { + pub(super) components: TypeIdMap, + pub(super) resources: TypeIdMap, + pub(super) dynamic_registrations: Vec, +} + +impl Debug for QueuedComponents { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let components = self + .components + .iter() + .map(|(type_id, queued)| (type_id, queued.id)) + .collect::>(); + let resources = self + .resources + .iter() + .map(|(type_id, queued)| (type_id, queued.id)) + .collect::>(); + let dynamic_registrations = self + .dynamic_registrations + .iter() + .map(|queued| queued.id) + .collect::>(); + write!(f, "components: {components:?}, resources: {resources:?}, dynamic_registrations: {dynamic_registrations:?}") + } +} + +/// A type that enables queuing registration in [`Components`]. +/// +/// # Note +/// +/// These queued registrations return [`ComponentId`]s. +/// These ids are not yet valid, but they will become valid +/// when either [`ComponentsRegistrator::apply_queued_registrations`] is called or the same registration is made directly. +/// In either case, the returned [`ComponentId`]s will be correct, but they are not correct yet. +/// +/// Generally, that means these [`ComponentId`]s can be safely used for read-only purposes. +/// Modifying the contents of the world through these [`ComponentId`]s directly without waiting for them to be fully registered +/// and without then confirming that they have been fully registered is not supported. +/// Hence, extra care is needed with these [`ComponentId`]s to ensure all safety rules are followed. +/// +/// As a rule of thumb, if you have mutable access to [`ComponentsRegistrator`], prefer to use that instead. +/// Use this only if you need to know the id of a component but do not need to modify the contents of the world based on that id. +#[derive(Clone, Copy)] +pub struct ComponentsQueuedRegistrator<'w> { + components: &'w Components, + ids: &'w ComponentIds, +} + +impl Deref for ComponentsQueuedRegistrator<'_> { + type Target = Components; + + fn deref(&self) -> &Self::Target { + self.components + } +} + +impl<'w> ComponentsQueuedRegistrator<'w> { + /// Constructs a new [`ComponentsQueuedRegistrator`]. + /// + /// # Safety + /// + /// The [`Components`] and [`ComponentIds`] must match. + /// For example, they must be from the same world. + pub unsafe fn new(components: &'w Components, ids: &'w ComponentIds) -> Self { + Self { components, ids } + } + + /// Queues this function to run as a component registrator. + /// + /// # Safety + /// + /// The [`TypeId`] must not already be registered or queued as a component. + unsafe fn force_register_arbitrary_component( + &self, + type_id: TypeId, + descriptor: ComponentDescriptor, + func: impl FnOnce(&mut ComponentsRegistrator, ComponentId, ComponentDescriptor) + 'static, + ) -> ComponentId { + let id = self.ids.next(); + self.components + .queued + .write() + .unwrap_or_else(PoisonError::into_inner) + .components + .insert( + type_id, + // SAFETY: The id was just generated. + unsafe { QueuedRegistration::new(id, descriptor, func) }, + ); + id + } + + /// Queues this function to run as a resource registrator. + /// + /// # Safety + /// + /// The [`TypeId`] must not already be registered or queued as a resource. + unsafe fn force_register_arbitrary_resource( + &self, + type_id: TypeId, + descriptor: ComponentDescriptor, + func: impl FnOnce(&mut ComponentsRegistrator, ComponentId, ComponentDescriptor) + 'static, + ) -> ComponentId { + let id = self.ids.next(); + self.components + .queued + .write() + .unwrap_or_else(PoisonError::into_inner) + .resources + .insert( + type_id, + // SAFETY: The id was just generated. + unsafe { QueuedRegistration::new(id, descriptor, func) }, + ); + id + } + + /// Queues this function to run as a dynamic registrator. + fn force_register_arbitrary_dynamic( + &self, + descriptor: ComponentDescriptor, + func: impl FnOnce(&mut ComponentsRegistrator, ComponentId, ComponentDescriptor) + 'static, + ) -> ComponentId { + let id = self.ids.next(); + self.components + .queued + .write() + .unwrap_or_else(PoisonError::into_inner) + .dynamic_registrations + .push( + // SAFETY: The id was just generated. + unsafe { QueuedRegistration::new(id, descriptor, func) }, + ); + id + } + + /// This is a queued version of [`ComponentsRegistrator::register_component`]. + /// This will reserve an id and queue the registration. + /// These registrations will be carried out at the next opportunity. + /// + /// If this has already been registered or queued, this returns the previous [`ComponentId`]. + /// + /// # Note + /// + /// Technically speaking, the returned [`ComponentId`] is not valid, but it will become valid later. + /// See type level docs for details. + #[inline] + pub fn queue_register_component(&self) -> ComponentId { + self.component_id::().unwrap_or_else(|| { + // SAFETY: We just checked that this type was not in the queue. + unsafe { + self.force_register_arbitrary_component( + TypeId::of::(), + ComponentDescriptor::new::(), + |registrator, id, _descriptor| { + // SAFETY: We just checked that this is not currently registered or queued, and if it was registered since, this would have been dropped from the queue. + #[expect(unused_unsafe, reason = "More precise to specify.")] + unsafe { + registrator.register_component_unchecked::(&mut Vec::new(), id); + } + }, + ) + } + }) + } + + /// This is a queued version of [`ComponentsRegistrator::register_component_with_descriptor`]. + /// This will reserve an id and queue the registration. + /// These registrations will be carried out at the next opportunity. + /// + /// # Note + /// + /// Technically speaking, the returned [`ComponentId`] is not valid, but it will become valid later. + /// See type level docs for details. + #[inline] + pub fn queue_register_component_with_descriptor( + &self, + descriptor: ComponentDescriptor, + ) -> ComponentId { + self.force_register_arbitrary_dynamic(descriptor, |registrator, id, descriptor| { + // SAFETY: Id uniqueness handled by caller. + unsafe { + registrator.register_component_inner(id, descriptor); + } + }) + } + + /// This is a queued version of [`ComponentsRegistrator::register_resource`]. + /// This will reserve an id and queue the registration. + /// These registrations will be carried out at the next opportunity. + /// + /// If this has already been registered or queued, this returns the previous [`ComponentId`]. + /// + /// # Note + /// + /// Technically speaking, the returned [`ComponentId`] is not valid, but it will become valid later. + /// See type level docs for details. + #[inline] + pub fn queue_register_resource(&self) -> ComponentId { + let type_id = TypeId::of::(); + self.get_resource_id(type_id).unwrap_or_else(|| { + // SAFETY: We just checked that this type was not in the queue. + unsafe { + self.force_register_arbitrary_resource( + type_id, + ComponentDescriptor::new_resource::(), + move |registrator, id, descriptor| { + // SAFETY: We just checked that this is not currently registered or queued, and if it was registered since, this would have been dropped from the queue. + // SAFETY: Id uniqueness handled by caller, and the type_id matches descriptor. + #[expect(unused_unsafe, reason = "More precise to specify.")] + unsafe { + registrator.register_resource_unchecked(type_id, id, descriptor); + } + }, + ) + } + }) + } + + /// This is a queued version of [`ComponentsRegistrator::register_non_send`]. + /// This will reserve an id and queue the registration. + /// These registrations will be carried out at the next opportunity. + /// + /// If this has already been registered or queued, this returns the previous [`ComponentId`]. + /// + /// # Note + /// + /// Technically speaking, the returned [`ComponentId`] is not valid, but it will become valid later. + /// See type level docs for details. + #[inline] + pub fn queue_register_non_send(&self) -> ComponentId { + let type_id = TypeId::of::(); + self.get_resource_id(type_id).unwrap_or_else(|| { + // SAFETY: We just checked that this type was not in the queue. + unsafe { + self.force_register_arbitrary_resource( + type_id, + ComponentDescriptor::new_non_send::(StorageType::default()), + move |registrator, id, descriptor| { + // SAFETY: We just checked that this is not currently registered or queued, and if it was registered since, this would have been dropped from the queue. + // SAFETY: Id uniqueness handled by caller, and the type_id matches descriptor. + #[expect(unused_unsafe, reason = "More precise to specify.")] + unsafe { + registrator.register_resource_unchecked(type_id, id, descriptor); + } + }, + ) + } + }) + } + + /// This is a queued version of [`ComponentsRegistrator::register_resource_with_descriptor`]. + /// This will reserve an id and queue the registration. + /// These registrations will be carried out at the next opportunity. + /// + /// # Note + /// + /// Technically speaking, the returned [`ComponentId`] is not valid, but it will become valid later. + /// See type level docs for details. + #[inline] + pub fn queue_register_resource_with_descriptor( + &self, + descriptor: ComponentDescriptor, + ) -> ComponentId { + self.force_register_arbitrary_dynamic(descriptor, |registrator, id, descriptor| { + // SAFETY: Id uniqueness handled by caller. + unsafe { + registrator.register_component_inner(id, descriptor); + } + }) + } +} diff --git a/crates/bevy_ecs/src/component/required.rs b/crates/bevy_ecs/src/component/required.rs new file mode 100644 index 0000000000..d46b6b61ce --- /dev/null +++ b/crates/bevy_ecs/src/component/required.rs @@ -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( + &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::>()) + { + // `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( + &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( + &mut self, + required_components: &mut RequiredComponents, + constructor: fn() -> R, + inheritance_depth: u16, + recursion_check_stack: &mut Vec, + ) { + let requiree = self.register_component_checked::(recursion_check_stack); + let required = self.register_component_checked::(recursion_check_stack); + + // SAFETY: We just created the components. + unsafe { + self.register_required_components_manual_unchecked::( + 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, +); + +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); + +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( + &mut self, + components: &mut ComponentsRegistrator, + constructor: fn() -> C, + inheritance_depth: u16, + ) { + let component_id = components.register_component::(); + 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({ + // `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 = Box; + + #[cfg(target_has_atomic = "ptr")] + type Intermediate = Arc; + + let boxed: Intermediate = 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 + '_ { + 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::>() + .join(" → "), + if direct_recursion { + format!( + "Remove require({}).", + components.get_name(requiree).unwrap().shortname() + ) + } else { + "If this is intentional, consider merging the components.".into() + } + ); + } + } +} diff --git a/crates/bevy_ecs/src/component/tick.rs b/crates/bevy_ecs/src/component/tick.rs new file mode 100644 index 0000000000..09d82a13d4 --- /dev/null +++ b/crates/bevy_ecs/src/component/tick.rs @@ -0,0 +1,199 @@ +use bevy_ecs_macros::Event; +use bevy_ptr::UnsafeCellDeref; +#[cfg(feature = "bevy_reflect")] +use bevy_reflect::Reflect; +use core::cell::UnsafeCell; + +use crate::change_detection::MAX_CHANGE_AGE; + +/// A value that tracks when a system ran relative to other systems. +/// This is used to power change detection. +/// +/// *Note* that a system that hasn't been run yet has a `Tick` of 0. +#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq)] +#[cfg_attr( + feature = "bevy_reflect", + derive(Reflect), + reflect(Debug, Hash, PartialEq, Clone) +)] +pub struct Tick { + tick: u32, +} + +impl Tick { + /// The maximum relative age for a change tick. + /// The value of this is equal to [`MAX_CHANGE_AGE`]. + /// + /// Since change detection will not work for any ticks older than this, + /// ticks are periodically scanned to ensure their relative values are below this. + pub const MAX: Self = Self::new(MAX_CHANGE_AGE); + + /// Creates a new [`Tick`] wrapping the given value. + #[inline] + pub const fn new(tick: u32) -> Self { + Self { tick } + } + + /// Gets the value of this change tick. + #[inline] + pub const fn get(self) -> u32 { + self.tick + } + + /// Sets the value of this change tick. + #[inline] + pub fn set(&mut self, tick: u32) { + self.tick = tick; + } + + /// Returns `true` if this `Tick` occurred since the system's `last_run`. + /// + /// `this_run` is the current tick of the system, used as a reference to help deal with wraparound. + #[inline] + pub fn is_newer_than(self, last_run: Tick, this_run: Tick) -> bool { + // This works even with wraparound because the world tick (`this_run`) is always "newer" than + // `last_run` and `self.tick`, and we scan periodically to clamp `ComponentTicks` values + // so they never get older than `u32::MAX` (the difference would overflow). + // + // The clamp here ensures determinism (since scans could differ between app runs). + let ticks_since_insert = this_run.relative_to(self).tick.min(MAX_CHANGE_AGE); + let ticks_since_system = this_run.relative_to(last_run).tick.min(MAX_CHANGE_AGE); + + ticks_since_system > ticks_since_insert + } + + /// Returns a change tick representing the relationship between `self` and `other`. + #[inline] + pub(crate) fn relative_to(self, other: Self) -> Self { + let tick = self.tick.wrapping_sub(other.tick); + Self { tick } + } + + /// Wraps this change tick's value if it exceeds [`Tick::MAX`]. + /// + /// Returns `true` if wrapping was performed. Otherwise, returns `false`. + #[inline] + pub fn check_tick(&mut self, check: CheckChangeTicks) -> bool { + let age = check.present_tick().relative_to(*self); + // This comparison assumes that `age` has not overflowed `u32::MAX` before, which will be true + // so long as this check always runs before that can happen. + if age.get() > Self::MAX.get() { + *self = check.present_tick().relative_to(Self::MAX); + true + } else { + false + } + } +} + +/// An observer [`Event`] that can be used to maintain [`Tick`]s in custom data structures, enabling to make +/// use of bevy's periodic checks that clamps ticks to a certain range, preventing overflows and thus +/// keeping methods like [`Tick::is_newer_than`] reliably return `false` for ticks that got too old. +/// +/// # Example +/// +/// Here a schedule is stored in a custom resource. This way the systems in it would not have their change +/// ticks automatically updated via [`World::check_change_ticks`](crate::world::World::check_change_ticks), +/// possibly causing `Tick`-related bugs on long-running apps. +/// +/// To fix that, add an observer for this event that calls the schedule's +/// [`Schedule::check_change_ticks`](bevy_ecs::schedule::Schedule::check_change_ticks). +/// +/// ``` +/// use bevy_ecs::prelude::*; +/// use bevy_ecs::component::CheckChangeTicks; +/// +/// #[derive(Resource)] +/// struct CustomSchedule(Schedule); +/// +/// # let mut world = World::new(); +/// world.add_observer(|check: On, mut schedule: ResMut| { +/// schedule.0.check_change_ticks(*check); +/// }); +/// ``` +#[derive(Debug, Clone, Copy, Event)] +pub struct CheckChangeTicks(pub(crate) Tick); + +impl CheckChangeTicks { + /// Get the present `Tick` that other ticks get compared to. + pub fn present_tick(self) -> Tick { + self.0 + } +} + +/// Interior-mutable access to the [`Tick`]s for a single component or resource. +#[derive(Copy, Clone, Debug)] +pub struct TickCells<'a> { + /// The tick indicating when the value was added to the world. + pub added: &'a UnsafeCell, + /// The tick indicating the last time the value was modified. + pub changed: &'a UnsafeCell, +} + +impl<'a> TickCells<'a> { + /// # Safety + /// All cells contained within must uphold the safety invariants of [`UnsafeCellDeref::read`]. + #[inline] + pub(crate) unsafe fn read(&self) -> ComponentTicks { + ComponentTicks { + // SAFETY: The callers uphold the invariants for `read`. + added: unsafe { self.added.read() }, + // SAFETY: The callers uphold the invariants for `read`. + changed: unsafe { self.changed.read() }, + } + } +} + +/// Records when a component or resource was added and when it was last mutably dereferenced (or added). +#[derive(Copy, Clone, Debug)] +#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, Clone))] +pub struct ComponentTicks { + /// Tick recording the time this component or resource was added. + pub added: Tick, + + /// Tick recording the time this component or resource was most recently changed. + pub changed: Tick, +} + +impl ComponentTicks { + /// Returns `true` if the component or resource was added after the system last ran + /// (or the system is running for the first time). + #[inline] + pub fn is_added(&self, last_run: Tick, this_run: Tick) -> bool { + self.added.is_newer_than(last_run, this_run) + } + + /// Returns `true` if the component or resource was added or mutably dereferenced after the system last ran + /// (or the system is running for the first time). + #[inline] + pub fn is_changed(&self, last_run: Tick, this_run: Tick) -> bool { + self.changed.is_newer_than(last_run, this_run) + } + + /// Creates a new instance with the same change tick for `added` and `changed`. + pub fn new(change_tick: Tick) -> Self { + Self { + added: change_tick, + changed: change_tick, + } + } + + /// Manually sets the change tick. + /// + /// This is normally done automatically via the [`DerefMut`](core::ops::DerefMut) implementation + /// on [`Mut`](crate::change_detection::Mut), [`ResMut`](crate::change_detection::ResMut), etc. + /// However, components and resources that make use of interior mutability might require manual updates. + /// + /// # Example + /// ```no_run + /// # use bevy_ecs::{world::World, component::ComponentTicks}; + /// let world: World = unimplemented!(); + /// let component_ticks: ComponentTicks = unimplemented!(); + /// + /// component_ticks.set_changed(world.read_change_tick()); + /// ``` + #[inline] + pub fn set_changed(&mut self, change_tick: Tick) { + self.changed = change_tick; + } +} diff --git a/crates/bevy_ecs/src/entity/mod.rs b/crates/bevy_ecs/src/entity/mod.rs index 700a4e517f..64a8c8952e 100644 --- a/crates/bevy_ecs/src/entity/mod.rs +++ b/crates/bevy_ecs/src/entity/mod.rs @@ -615,42 +615,16 @@ impl<'de> Deserialize<'de> for Entity { } } -/// Outputs the full entity identifier, including the index, generation, and the raw bits. +/// Outputs the short entity identifier, including the index and generation. /// -/// This takes the format: `{index}v{generation}#{bits}`. +/// This takes the format: `{index}v{generation}`. /// /// For [`Entity::PLACEHOLDER`], this outputs `PLACEHOLDER`. /// -/// # Usage -/// -/// Prefer to use this format for debugging and logging purposes. Because the output contains -/// the raw bits, it is easy to check it against serialized scene data. -/// -/// Example serialized scene data: -/// ```text -/// ( -/// ... -/// entities: { -/// 4294967297: ( <--- Raw Bits -/// components: { -/// ... -/// ), -/// ... -/// ) -/// ``` +/// For a unique [`u64`] representation, use [`Entity::to_bits`]. impl fmt::Debug for Entity { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self == &Self::PLACEHOLDER { - write!(f, "PLACEHOLDER") - } else { - write!( - f, - "{}v{}#{}", - self.index(), - self.generation(), - self.to_bits() - ) - } + fmt::Display::fmt(self, f) } } @@ -1645,7 +1619,7 @@ mod tests { fn entity_debug() { let entity = Entity::from_raw(EntityRow::new(NonMaxU32::new(42).unwrap())); let string = format!("{entity:?}"); - assert_eq!(string, "42v0#4294967253"); + assert_eq!(string, "42v0"); let entity = Entity::PLACEHOLDER; let string = format!("{entity:?}"); diff --git a/crates/bevy_pbr/src/pbr_material.rs b/crates/bevy_pbr/src/pbr_material.rs index 0207a81ed0..d7baef3a9a 100644 --- a/crates/bevy_pbr/src/pbr_material.rs +++ b/crates/bevy_pbr/src/pbr_material.rs @@ -386,6 +386,23 @@ pub struct StandardMaterial { /// /// [`Mesh::generate_tangents`]: bevy_render::mesh::Mesh::generate_tangents /// [`Mesh::with_generated_tangents`]: bevy_render::mesh::Mesh::with_generated_tangents + /// + /// # Usage + /// + /// ``` + /// # use bevy_asset::{AssetServer, Handle}; + /// # use bevy_ecs::change_detection::Res; + /// # use bevy_image::{Image, ImageLoaderSettings}; + /// # + /// fn load_normal_map(asset_server: Res) { + /// let normal_handle: Handle = asset_server.load_with_settings( + /// "textures/parallax_example/cube_normal.png", + /// // The normal map texture is in linear color space. Lighting won't look correct + /// // if `is_srgb` is `true`, which is the default. + /// |settings: &mut ImageLoaderSettings| settings.is_srgb = false, + /// ); + /// } + /// ``` #[texture(9)] #[sampler(10)] #[dependency] diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 53b3b4129a..9795d442dd 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -3016,7 +3016,7 @@ impl RenderCommand

for SetMeshBindGroup { ); }; - let mut dynamic_offsets: [u32; 3] = Default::default(); + let mut dynamic_offsets: [u32; 5] = Default::default(); let mut offset_count = 0; if let PhaseItemExtraIndex::DynamicOffset(dynamic_offset) = item.extra_index() { dynamic_offsets[offset_count] = dynamic_offset; diff --git a/crates/bevy_pbr/src/render/pbr_fragment.wgsl b/crates/bevy_pbr/src/render/pbr_fragment.wgsl index 779546f8bd..3c69c4405f 100644 --- a/crates/bevy_pbr/src/render/pbr_fragment.wgsl +++ b/crates/bevy_pbr/src/render/pbr_fragment.wgsl @@ -377,7 +377,6 @@ fn pbr_input_from_standard_material( var perceptual_roughness: f32 = pbr_bindings::material.perceptual_roughness; #endif // BINDLESS - let roughness = lighting::perceptualRoughnessToRoughness(perceptual_roughness); #ifdef VERTEX_UVS if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_METALLIC_ROUGHNESS_TEXTURE_BIT) != 0u) { let metallic_roughness = @@ -627,7 +626,7 @@ fn pbr_input_from_standard_material( var specular_occlusion: f32 = 1.0; #ifdef VERTEX_UVS if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_OCCLUSION_TEXTURE_BIT) != 0u) { - diffuse_occlusion *= + diffuse_occlusion *= #ifdef MESHLET_MESH_MATERIAL_PASS textureSampleGrad( #else // MESHLET_MESH_MATERIAL_PASS @@ -660,7 +659,8 @@ fn pbr_input_from_standard_material( diffuse_occlusion = min(diffuse_occlusion, ssao_multibounce); // Use SSAO to estimate the specular occlusion. // Lagarde and Rousiers 2014, "Moving Frostbite to Physically Based Rendering" - specular_occlusion = saturate(pow(NdotV + ssao, exp2(-16.0 * roughness - 1.0)) - 1.0 + ssao); + let roughness = lighting::perceptualRoughnessToRoughness(pbr_input.material.perceptual_roughness); + specular_occlusion = saturate(pow(NdotV + ssao, exp2(-16.0 * roughness - 1.0)) - 1.0 + ssao); #endif pbr_input.diffuse_occlusion = diffuse_occlusion; pbr_input.specular_occlusion = specular_occlusion; diff --git a/crates/bevy_pbr/src/render/pbr_lighting.wgsl b/crates/bevy_pbr/src/render/pbr_lighting.wgsl index 17cae13b92..6bc24d8af0 100644 --- a/crates/bevy_pbr/src/render/pbr_lighting.wgsl +++ b/crates/bevy_pbr/src/render/pbr_lighting.wgsl @@ -235,16 +235,13 @@ fn fresnel(f0: vec3, LdotH: f32) -> vec3 { // Multiscattering approximation: // fn specular_multiscatter( - input: ptr, D: f32, V: f32, F: vec3, + F0: vec3, + F_ab: vec2, specular_intensity: f32, ) -> vec3 { - // Unpack. - let F0 = (*input).F0_; - let F_ab = (*input).F_ab; - var Fr = (specular_intensity * D * V) * F; Fr *= 1.0 + F0 * (1.0 / F_ab.x - 1.0); return Fr; @@ -329,7 +326,7 @@ fn specular( let F = fresnel(F0, LdotH); // Calculate the specular light. - let Fr = specular_multiscatter(input, D, V, F, specular_intensity); + let Fr = specular_multiscatter(D, V, F, F0, (*input).F_ab, specular_intensity); return Fr; } @@ -397,7 +394,7 @@ fn specular_anisotropy( let Fa = fresnel(F0, LdotH); // Calculate the specular light. - let Fr = specular_multiscatter(input, Da, Va, Fa, specular_intensity); + let Fr = specular_multiscatter(Da, Va, Fa, F0, (*input).F_ab, specular_intensity); return Fr; } @@ -482,7 +479,7 @@ fn cubemap_uv(direction: vec3, cubemap_type: u32) -> vec2 { ), max_axis != abs_direction.x ); - + var face_uv: vec2; var divisor: f32; var corner_uv: vec2 = vec2(0, 0); @@ -500,12 +497,12 @@ fn cubemap_uv(direction: vec3, cubemap_type: u32) -> vec2 { face_uv = (face_uv / divisor) * 0.5 + 0.5; switch cubemap_type { - case CUBEMAP_TYPE_CROSS_VERTICAL: { - face_size = vec2(1.0/3.0, 1.0/4.0); + case CUBEMAP_TYPE_CROSS_VERTICAL: { + face_size = vec2(1.0/3.0, 1.0/4.0); corner_uv = vec2((0x111102u >> (4 * face_index)) & 0xFu, (0x132011u >> (4 * face_index)) & 0xFu); } - case CUBEMAP_TYPE_CROSS_HORIZONTAL: { - face_size = vec2(1.0/4.0, 1.0/3.0); + case CUBEMAP_TYPE_CROSS_HORIZONTAL: { + face_size = vec2(1.0/4.0, 1.0/3.0); corner_uv = vec2((0x131102u >> (4 * face_index)) & 0xFu, (0x112011u >> (4 * face_index)) & 0xFu); } case CUBEMAP_TYPE_SEQUENCE_HORIZONTAL: { @@ -765,7 +762,7 @@ fn directional_light( view_bindings::clustered_decal_sampler, decal_uv - floor(decal_uv), 0.0 - ).r; + ).r; } else { texture_sample = 0f; } diff --git a/crates/bevy_pbr/src/render/shadow_sampling.wgsl b/crates/bevy_pbr/src/render/shadow_sampling.wgsl index c7f7253a63..2b35e57037 100644 --- a/crates/bevy_pbr/src/render/shadow_sampling.wgsl +++ b/crates/bevy_pbr/src/render/shadow_sampling.wgsl @@ -422,11 +422,7 @@ fn sample_shadow_cubemap_gaussian( ) -> f32 { // Create an orthonormal basis so we can apply a 2D sampling pattern to a // cubemap. - var up = vec3(0.0, 1.0, 0.0); - if (dot(up, normalize(light_local)) > 0.99) { - up = vec3(1.0, 0.0, 0.0); // Avoid creating a degenerate basis. - } - let basis = orthonormalize(light_local, up) * scale * distance_to_light; + let basis = orthonormalize(normalize(light_local)) * scale * distance_to_light; var sum: f32 = 0.0; sum += sample_shadow_cubemap_at_offset( @@ -469,11 +465,7 @@ fn sample_shadow_cubemap_jittered( ) -> f32 { // Create an orthonormal basis so we can apply a 2D sampling pattern to a // cubemap. - var up = vec3(0.0, 1.0, 0.0); - if (dot(up, normalize(light_local)) > 0.99) { - up = vec3(1.0, 0.0, 0.0); // Avoid creating a degenerate basis. - } - let basis = orthonormalize(light_local, up) * scale * distance_to_light; + let basis = orthonormalize(normalize(light_local)) * scale * distance_to_light; let rotation_matrix = random_rotation_matrix(vec2(1.0), temporal); @@ -553,11 +545,7 @@ fn search_for_blockers_in_shadow_cubemap( ) -> f32 { // Create an orthonormal basis so we can apply a 2D sampling pattern to a // cubemap. - var up = vec3(0.0, 1.0, 0.0); - if (dot(up, normalize(light_local)) > 0.99) { - up = vec3(1.0, 0.0, 0.0); // Avoid creating a degenerate basis. - } - let basis = orthonormalize(light_local, up) * scale * distance_to_light; + let basis = orthonormalize(normalize(light_local)) * scale * distance_to_light; var sum: vec2 = vec2(0.0); sum += search_for_blockers_in_shadow_cubemap_at_offset( diff --git a/crates/bevy_render/src/maths.wgsl b/crates/bevy_render/src/maths.wgsl index d1e35523dc..0f9a11076f 100644 --- a/crates/bevy_render/src/maths.wgsl +++ b/crates/bevy_render/src/maths.wgsl @@ -63,17 +63,19 @@ fn mat4x4_to_mat3x3(m: mat4x4) -> mat3x3 { return mat3x3(m[0].xyz, m[1].xyz, m[2].xyz); } -// Creates an orthonormal basis given a Z vector and an up vector (which becomes -// Y after orthonormalization). +// Creates an orthonormal basis given a normalized Z vector. // // The results are equivalent to the Gram-Schmidt process [1]. // // [1]: https://math.stackexchange.com/a/1849294 -fn orthonormalize(z_unnormalized: vec3, up: vec3) -> mat3x3 { - let z_basis = normalize(z_unnormalized); - let x_basis = normalize(cross(z_basis, up)); - let y_basis = cross(z_basis, x_basis); - return mat3x3(x_basis, y_basis, z_basis); +fn orthonormalize(z_normalized: vec3) -> mat3x3 { + var up = vec3(0.0, 1.0, 0.0); + if (abs(dot(up, z_normalized)) > 0.99) { + up = vec3(1.0, 0.0, 0.0); // Avoid creating a degenerate basis. + } + let x_basis = normalize(cross(z_normalized, up)); + let y_basis = cross(z_normalized, x_basis); + return mat3x3(x_basis, y_basis, z_normalized); } // Returns true if any part of a sphere is on the positive side of a plane. diff --git a/crates/bevy_render/src/renderer/mod.rs b/crates/bevy_render/src/renderer/mod.rs index 6871f8cc56..ab46b6f269 100644 --- a/crates/bevy_render/src/renderer/mod.rs +++ b/crates/bevy_render/src/renderer/mod.rs @@ -7,7 +7,7 @@ use bevy_tasks::ComputeTaskPool; use bevy_utils::WgpuWrapper; pub use graph_runner::*; pub use render_device::*; -use tracing::{debug, error, info, info_span, trace, warn}; +use tracing::{debug, error, info, info_span, warn}; use crate::{ diagnostic::{internal::DiagnosticsRecorder, RecordDiagnostics}, @@ -145,6 +145,33 @@ const GPU_NOT_FOUND_ERROR_MESSAGE: &str = if cfg!(target_os = "linux") { "Unable to find a GPU! Make sure you have installed required drivers!" }; +#[cfg(not(target_family = "wasm"))] +fn find_adapter_by_name( + instance: &Instance, + options: &WgpuSettings, + compatible_surface: Option<&wgpu::Surface<'_>>, + adapter_name: &str, +) -> Option { + for adapter in + instance.enumerate_adapters(options.backends.expect( + "The `backends` field of `WgpuSettings` must be set to use a specific adapter.", + )) + { + tracing::trace!("Checking adapter: {:?}", adapter.get_info()); + let info = adapter.get_info(); + if let Some(surface) = compatible_surface { + if !adapter.is_surface_supported(surface) { + continue; + } + } + + if info.name.eq_ignore_ascii_case(adapter_name) { + return Some(adapter); + } + } + None +} + /// Initializes the renderer by retrieving and preparing the GPU instance, device and queue /// for the specified backend. pub async fn initialize_renderer( @@ -154,36 +181,30 @@ pub async fn initialize_renderer( desired_adapter_name: Option, #[cfg(feature = "dlss")] dlss_project_id: bevy_asset::uuid::Uuid, ) -> RenderResources { + #[cfg(not(target_family = "wasm"))] + let mut selected_adapter = desired_adapter_name.and_then(|adapter_name| { + find_adapter_by_name( + &instance, + options, + request_adapter_options.compatible_surface, + &adapter_name, + ) + }); + #[cfg(target_family = "wasm")] let mut selected_adapter = None; - if let Some(adapter_name) = &desired_adapter_name { - debug!("Searching for adapter with name: {}", adapter_name); - for adapter in instance.enumerate_adapters(options.backends.expect( - "The `backends` field of `WgpuSettings` must be set to use a specific adapter.", - )) { - trace!("Checking adapter: {:?}", adapter.get_info()); - let info = adapter.get_info(); - if let Some(surface) = request_adapter_options.compatible_surface { - if !adapter.is_surface_supported(surface) { - continue; - } - } - if info - .name - .to_lowercase() - .contains(&adapter_name.to_lowercase()) - { - selected_adapter = Some(adapter); - break; - } - } - } else { + #[cfg(target_family = "wasm")] + if desired_adapter_name.is_some() { + warn!("Choosing an adapter is not supported on wasm."); + } + + if selected_adapter.is_none() { debug!( "Searching for adapter with options: {:?}", request_adapter_options ); selected_adapter = instance.request_adapter(request_adapter_options).await.ok(); - }; + } let adapter = selected_adapter.expect(GPU_NOT_FOUND_ERROR_MESSAGE); let adapter_info = adapter.get_info(); diff --git a/crates/bevy_solari/src/lib.rs b/crates/bevy_solari/src/lib.rs index d5a22e014b..686cfd3238 100644 --- a/crates/bevy_solari/src/lib.rs +++ b/crates/bevy_solari/src/lib.rs @@ -2,7 +2,7 @@ //! Provides raytraced lighting. //! -//! See [`SolariPlugin`] for more info. +//! See [`SolariPlugins`] for more info. //! //! ![`bevy_solari` logo](https://raw.githubusercontent.com/bevyengine/bevy/assets/branding/bevy_solari.svg) pub mod pathtracer; @@ -13,33 +13,35 @@ pub mod scene; /// /// This includes the most common types in this crate, re-exported for your convenience. pub mod prelude { - pub use super::SolariPlugin; + pub use super::SolariPlugins; pub use crate::realtime::SolariLighting; pub use crate::scene::RaytracingMesh3d; } use crate::realtime::SolariLightingPlugin; use crate::scene::RaytracingScenePlugin; -use bevy_app::{App, Plugin}; +use bevy_app::{PluginGroup, PluginGroupBuilder}; use bevy_render::settings::WgpuFeatures; -/// An experimental plugin for raytraced lighting. +/// An experimental set of plugins for raytraced lighting. /// -/// This plugin provides: +/// This plugin group provides: /// * [`SolariLightingPlugin`] - Raytraced direct and indirect lighting (indirect lighting not yet implemented). /// * [`RaytracingScenePlugin`] - BLAS building, resource and lighting binding. -/// * [`pathtracer::PathtracingPlugin`] - A non-realtime pathtracer for validation purposes. +/// * [`pathtracer::PathtracingPlugin`] - A non-realtime pathtracer for validation purposes (not added by default). /// /// To get started, add `RaytracingMesh3d` and `MeshMaterial3d::` to your entities. -pub struct SolariPlugin; +pub struct SolariPlugins; -impl Plugin for SolariPlugin { - fn build(&self, app: &mut App) { - app.add_plugins((RaytracingScenePlugin, SolariLightingPlugin)); +impl PluginGroup for SolariPlugins { + fn build(self) -> PluginGroupBuilder { + PluginGroupBuilder::start::() + .add(RaytracingScenePlugin) + .add(SolariLightingPlugin) } } -impl SolariPlugin { +impl SolariPlugins { /// [`WgpuFeatures`] required for this plugin to function. pub fn required_wgpu_features() -> WgpuFeatures { WgpuFeatures::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE diff --git a/crates/bevy_solari/src/pathtracer/mod.rs b/crates/bevy_solari/src/pathtracer/mod.rs index 30cc15ba10..72affe4b04 100644 --- a/crates/bevy_solari/src/pathtracer/mod.rs +++ b/crates/bevy_solari/src/pathtracer/mod.rs @@ -2,7 +2,7 @@ mod extract; mod node; mod prepare; -use crate::SolariPlugin; +use crate::SolariPlugins; use bevy_app::{App, Plugin}; use bevy_asset::embedded_asset; use bevy_core_pipeline::core_3d::graph::{Core3d, Node3d}; @@ -37,10 +37,10 @@ impl Plugin for PathtracingPlugin { let render_device = render_app.world().resource::(); let features = render_device.features(); - if !features.contains(SolariPlugin::required_wgpu_features()) { + if !features.contains(SolariPlugins::required_wgpu_features()) { warn!( "PathtracingPlugin not loaded. GPU lacks support for required features: {:?}.", - SolariPlugin::required_wgpu_features().difference(features) + SolariPlugins::required_wgpu_features().difference(features) ); return; } diff --git a/crates/bevy_solari/src/realtime/mod.rs b/crates/bevy_solari/src/realtime/mod.rs index a8d6235f30..16e4f0ddbd 100644 --- a/crates/bevy_solari/src/realtime/mod.rs +++ b/crates/bevy_solari/src/realtime/mod.rs @@ -2,7 +2,7 @@ mod extract; mod node; mod prepare; -use crate::SolariPlugin; +use crate::SolariPlugins; use bevy_app::{App, Plugin}; use bevy_asset::embedded_asset; use bevy_core_pipeline::{ @@ -38,10 +38,10 @@ impl Plugin for SolariLightingPlugin { let render_device = render_app.world().resource::(); let features = render_device.features(); - if !features.contains(SolariPlugin::required_wgpu_features()) { + if !features.contains(SolariPlugins::required_wgpu_features()) { warn!( "SolariLightingPlugin not loaded. GPU lacks support for required features: {:?}.", - SolariPlugin::required_wgpu_features().difference(features) + SolariPlugins::required_wgpu_features().difference(features) ); return; } diff --git a/crates/bevy_solari/src/scene/mod.rs b/crates/bevy_solari/src/scene/mod.rs index a68e126480..f1af566c1c 100644 --- a/crates/bevy_solari/src/scene/mod.rs +++ b/crates/bevy_solari/src/scene/mod.rs @@ -6,7 +6,7 @@ mod types; pub use binder::RaytracingSceneBindings; pub use types::RaytracingMesh3d; -use crate::SolariPlugin; +use crate::SolariPlugins; use bevy_app::{App, Plugin}; use bevy_ecs::schedule::IntoScheduleConfigs; use bevy_render::{ @@ -41,10 +41,10 @@ impl Plugin for RaytracingScenePlugin { let render_app = app.sub_app_mut(RenderApp); let render_device = render_app.world().resource::(); let features = render_device.features(); - if !features.contains(SolariPlugin::required_wgpu_features()) { + if !features.contains(SolariPlugins::required_wgpu_features()) { warn!( "RaytracingScenePlugin not loaded. GPU lacks support for required features: {:?}.", - SolariPlugin::required_wgpu_features().difference(features) + SolariPlugins::required_wgpu_features().difference(features) ); return; } diff --git a/crates/bevy_ui/src/focus.rs b/crates/bevy_ui/src/focus.rs index 384661f4d1..32872f1447 100644 --- a/crates/bevy_ui/src/focus.rs +++ b/crates/bevy_ui/src/focus.rs @@ -1,10 +1,12 @@ -use crate::{ui_transform::UiGlobalTransform, ComputedNode, ComputedNodeTarget, Node, UiStack}; +use crate::{ + ui_transform::UiGlobalTransform, ComputedNode, ComputedNodeTarget, Node, OverrideClip, UiStack, +}; use bevy_ecs::{ change_detection::DetectChangesMut, entity::{ContainsEntity, Entity}, hierarchy::ChildOf, prelude::{Component, With}, - query::QueryData, + query::{QueryData, Without}, reflect::ReflectComponent, system::{Local, Query, Res}, }; @@ -157,7 +159,7 @@ pub fn ui_focus_system( ui_stack: Res, mut node_query: Query, clipping_query: Query<(&ComputedNode, &UiGlobalTransform, &Node)>, - child_of_query: Query<&ChildOf>, + child_of_query: Query<&ChildOf, Without>, ) { let primary_window = primary_window.iter().next(); @@ -325,11 +327,12 @@ pub fn ui_focus_system( } /// Walk up the tree child-to-parent checking that `point` is not clipped by any ancestor node. +/// If `entity` has an [`OverrideClip`] component it ignores any inherited clipping and returns true. pub fn clip_check_recursive( point: Vec2, entity: Entity, clipping_query: &Query<'_, '_, (&ComputedNode, &UiGlobalTransform, &Node)>, - child_of_query: &Query<&ChildOf>, + child_of_query: &Query<&ChildOf, Without>, ) -> bool { if let Ok(child_of) = child_of_query.get(entity) { let parent = child_of.0; diff --git a/crates/bevy_ui/src/gradients.rs b/crates/bevy_ui/src/gradients.rs index 7086b37416..87b7afc581 100644 --- a/crates/bevy_ui/src/gradients.rs +++ b/crates/bevy_ui/src/gradients.rs @@ -44,6 +44,24 @@ impl ColorStop { } } + /// A color stop with its position in logical pixels. + pub fn px(color: impl Into, px: f32) -> Self { + Self { + color: color.into(), + point: Val::Px(px), + hint: 0.5, + } + } + + /// A color stop with a percentage position. + pub fn percent(color: impl Into, percent: f32) -> Self { + Self { + color: color.into(), + point: Val::Percent(percent), + hint: 0.5, + } + } + // Set the interpolation midpoint between this and the following stop pub fn with_hint(mut self, hint: f32) -> Self { self.hint = hint; diff --git a/crates/bevy_ui/src/picking_backend.rs b/crates/bevy_ui/src/picking_backend.rs index ccd61a3807..891aea7d35 100644 --- a/crates/bevy_ui/src/picking_backend.rs +++ b/crates/bevy_ui/src/picking_backend.rs @@ -109,7 +109,7 @@ pub fn ui_picking( node_query: Query, mut output: EventWriter, clipping_query: Query<(&ComputedNode, &UiGlobalTransform, &Node)>, - child_of_query: Query<&ChildOf>, + child_of_query: Query<&ChildOf, Without>, ) { // For each camera, the pointer and its position let mut pointer_pos_by_camera = HashMap::>::default(); diff --git a/examples/3d/3d_viewport_to_world.rs b/examples/3d/3d_viewport_to_world.rs index 9aabd6f629..883121779a 100644 --- a/examples/3d/3d_viewport_to_world.rs +++ b/examples/3d/3d_viewport_to_world.rs @@ -13,41 +13,30 @@ fn main() { fn draw_cursor( camera_query: Single<(&Camera, &GlobalTransform)>, ground: Single<&GlobalTransform, With>, - windows: Query<&Window>, + window: Single<&Window>, mut gizmos: Gizmos, ) { - let Ok(windows) = windows.single() else { - return; - }; - let (camera, camera_transform) = *camera_query; - let Some(cursor_position) = windows.cursor_position() else { - return; - }; + if let Some(cursor_position) = window.cursor_position() + // Calculate a ray pointing from the camera into the world based on the cursor's position. + && let Ok(ray) = camera.viewport_to_world(camera_transform, cursor_position) + // Calculate if and at what distance the ray is hitting the ground plane. + && let Some(distance) = + ray.intersect_plane(ground.translation(), InfinitePlane3d::new(ground.up())) + { + let point = ray.get_point(distance); - // Calculate a ray pointing from the camera into the world based on the cursor's position. - let Ok(ray) = camera.viewport_to_world(camera_transform, cursor_position) else { - return; - }; - - // Calculate if and where the ray is hitting the ground plane. - let Some(distance) = - ray.intersect_plane(ground.translation(), InfinitePlane3d::new(ground.up())) - else { - return; - }; - let point = ray.get_point(distance); - - // Draw a circle just above the ground plane at that position. - gizmos.circle( - Isometry3d::new( - point + ground.up() * 0.01, - Quat::from_rotation_arc(Vec3::Z, ground.up().as_vec3()), - ), - 0.2, - Color::WHITE, - ); + // Draw a circle just above the ground plane at that position. + gizmos.circle( + Isometry3d::new( + point + ground.up() * 0.01, + Quat::from_rotation_arc(Vec3::Z, ground.up().as_vec3()), + ), + 0.2, + Color::WHITE, + ); + } } #[derive(Component)] diff --git a/examples/3d/solari.rs b/examples/3d/solari.rs index 895df4d6fd..417cfe4f30 100644 --- a/examples/3d/solari.rs +++ b/examples/3d/solari.rs @@ -10,7 +10,7 @@ use bevy::{ scene::SceneInstanceReady, solari::{ pathtracer::{Pathtracer, PathtracingPlugin}, - prelude::{RaytracingMesh3d, SolariLighting, SolariPlugin}, + prelude::{RaytracingMesh3d, SolariLighting, SolariPlugins}, }, }; use camera_controller::{CameraController, CameraControllerPlugin}; @@ -28,7 +28,7 @@ fn main() { let args: Args = argh::from_env(); let mut app = App::new(); - app.add_plugins((DefaultPlugins, SolariPlugin, CameraControllerPlugin)) + app.add_plugins((DefaultPlugins, SolariPlugins, CameraControllerPlugin)) .insert_resource(args) .add_systems(Startup, setup); diff --git a/examples/ui/feathers.rs b/examples/ui/feathers.rs index da8b1faf27..5b580483b6 100644 --- a/examples/ui/feathers.rs +++ b/examples/ui/feathers.rs @@ -1,7 +1,9 @@ //! This example shows off the various Bevy Feathers widgets. use bevy::{ - core_widgets::{Callback, CoreRadio, CoreRadioGroup, CoreWidgetsPlugins, SliderStep}, + core_widgets::{ + Callback, CoreRadio, CoreRadioGroup, CoreWidgetsPlugins, SliderPrecision, SliderStep, + }, feathers::{ controls::{ button, checkbox, radio, slider, toggle_switch, ButtonProps, ButtonVariant, @@ -259,7 +261,7 @@ fn demo_root(commands: &mut Commands) -> impl Bundle { value: 20.0, ..default() }, - SliderStep(10.) + (SliderStep(10.), SliderPrecision(2)), ), ] ),], diff --git a/release-content/migration-guides/render_startup.md b/release-content/migration-guides/render_startup.md new file mode 100644 index 0000000000..c1f20f78b3 --- /dev/null +++ b/release-content/migration-guides/render_startup.md @@ -0,0 +1,116 @@ +--- +title: Many render resources now initialized in `RenderStartup` +pull_requests: [19841, 19926, 19885, 19886, 19897, 19898, 19901] +--- + +Many render resources are **no longer present** during `Plugin::finish`. Instead they are +initialized during `RenderStartup` (which occurs once the app starts running). If you only access +the resource during the `Render` schedule, then there should be no change. However, if you need one +of these render resources to initialize your own resource, you will need to convert your resource +initialization into a system. + +The following are the (public) resources that are now initialized in `RenderStartup`. + +- `CasPipeline` +- `FxaaPipeline` +- `SmaaPipelines` +- `TaaPipeline` +- `BoxShadowPipeline` +- `GradientPipeline` +- `UiPipeline` +- `UiMaterialPipeline` +- `UiTextureSlicePipeline` + +The vast majority of cases for initializing render resources look like so (in Bevy 0.16): + +```rust +impl Plugin for MyRenderingPlugin { + fn build(&self, app: &mut App) { + // Do nothing?? + } + + fn finish(&self, app: &mut App) { + let Some(render_app) = app.get_sub_app_mut(RenderApp) else { + return; + }; + + render_app.init_resource::(); + render_app.add_systems(Render, my_render_system); + } +} + +pub struct MyRenderResource { + ... +} + +impl FromWorld for MyRenderResource { + fn from_world(world: &mut World) -> Self { + let render_device = world.resource::(); + let render_adapter = world.resource::(); + let asset_server = world.resource::(); + + MyRenderResource { + ... + } + } +} +``` + +The two main things to focus on are: + +1. The resource implements the `FromWorld` trait which collects all its dependent resources (most + commonly, `RenderDevice`), and then creates an instance of the resource. +2. The plugin adds its systems and resources in `Plugin::finish`. + +First, we need to rewrite our `FromWorld` implementation as a system. This generally means +converting calls to `World::resource` into system params, and then using `Commands` to insert the +resource. In the above case, that would look like: + +```rust +// Just a regular old system!! +fn init_my_resource( + mut commands: Commands, + render_device: Res, + render_adapter: Res, + asset_server: Res, +) { + commands.insert_resource(MyRenderResource { + ... + }); +} +``` + +Each case will be slightly different. Two notes to be wary of: + +1. Functions that accept `&RenderDevice` for example may no longer compile after switching to + `Res`. This can be resolved by passing `&render_device` instead of + `render_device`. +2. If you are using `load_embedded_asset(world, "my_asset.png")`, you may need to first add + `asset_server` as a system param, then change this to + `load_embedded_asset(asset_server.as_ref(), "my_asset.png")`. + +Now that we have our initialization system, we just need to add the system to `RenderStartup`: + +```rust +impl Plugin for MyRenderingPlugin { + fn build(&self, app: &mut App) { + let Some(render_app) = app.get_sub_app_mut(RenderApp) else { + return; + }; + + render_app + .add_systems(RenderStartup, init_my_resource) + .add_systems(Render, my_render_system); + } + + // No more finish!! +} +``` + +In addition, if your resource requires one of the affected systems above, you will need to use +system ordering to ensure your resource initializes after the other system. For example, if your +system uses `Res`, you will need to add an ordering like: + +```rust +render_app.add_systems(RenderStartup, init_my_resource.after(init_ui_pipeline)); +``` diff --git a/release-content/release-notes/headless-widgets.md b/release-content/release-notes/headless-widgets.md index 5b3ff3dc17..68f3978fbc 100644 --- a/release-content/release-notes/headless-widgets.md +++ b/release-content/release-notes/headless-widgets.md @@ -1,7 +1,7 @@ --- title: Headless Widgets authors: ["@viridia", "@ickshonpe", "@alice-i-cecile"] -pull_requests: [19366, 19584, 19665, 19778, 19803, 20036] +pull_requests: [19366, 19584, 19665, 19778, 19803, 20032, 20036] --- Bevy's `Button` and `Interaction` components have been around for a long time. Unfortunately diff --git a/release-content/release-notes/render_startup.md b/release-content/release-notes/render_startup.md new file mode 100644 index 0000000000..a97c68393d --- /dev/null +++ b/release-content/release-notes/render_startup.md @@ -0,0 +1,103 @@ +--- +title: `RenderStartup` and making the renderer my ECS-y +authors: ["@IceSentry", "@andriyDev"] +pull_requests: [19841, 19926, 19885, 19886, 19897, 19898, 19901] +--- + +Previous rendering code looked quite different from other Bevy code. In general, resources were +initialized with the `FromWorld` trait (where most Bevy code only uses the `Default` trait for most +resources) and systems/resources were added in `Plugin::finish` (where nearly all Bevy code does not +use `Plugin::finish` at all). This difference with Bevy code can make it harder for new developers +to learn rendering, and can result in "cargo cult" copying of rendering code (e.g., "is it important +to be using `FromWorld` here? Better to be safe and just do what the rendering code is doing!"). + +As a step towards making the renderer more accessible (and maintainable), we have introduced the +`RenderStartup` schedule and ported many rendering resources to be initialized in `RenderStartup` +with systems! This has several benefits: + +1. Creating resources in systems makes it clearer that rendering resources **are just regular + resources**. Hopefully, this better communicates that how you initialize these resources is + totally up to you! +2. We can now use the system ordering API to ensure that resources are initialized in the correct + order. For example, we can do `init_material_pipeline.after(init_mesh_pipeline)` if we need the + mesh pipeline to initialize the material pipeline. +3. These initialization systems clearly describe what resources they require through their argument + list. If a system has an argument of `deferred_lighting_layout: Res`, it + clearly documents that this system needs to be run **after** we initialize the + `DeferredLightingLayout`. + +We want developers to become more familiar and comfortable with Bevy's rendering stack, and hope +that bringing the renderer closer to regular ECS code will encourage that. Code that previously looked +like this (in Bevy 0.16): + +```rust +impl Plugin for MyRenderingPlugin { + fn build(&self, app: &mut App) { + // Do nothing?? + } + + fn finish(&self, app: &mut App) { + let Some(render_app) = app.get_sub_app_mut(RenderApp) else { + return; + }; + + render_app.init_resource::(); + } +} + +pub struct MyRenderResource { + ... +} + +impl FromWorld for MyRenderResource { + fn from_world(world: &mut World) -> Self { + let render_device = world.resource::(); + let render_adapter = world.resource::(); + let asset_server = world.resource::(); + + MyRenderResource { + ... + } + } +} +``` + +Can now be written like: + +```rust +impl Plugin for MyRenderingPlugin { + fn build(&self, app: &mut App) { + let Some(render_app) = app.get_sub_app_mut(RenderApp) else { + return; + }; + + render_app.add_systems(RenderStartup, init_my_resource); + } + + // No more finish!! +} + +pub struct MyRenderResource { + ... +} + +// Just a regular old system!! +fn init_my_resource( + mut commands: Commands, + render_device: Res, + render_adapter: Res, + asset_server: Res, +) { + commands.insert_resource(MyRenderResource { + ... + }); +} +``` + +We highly encourage users to port their own rendering resources to this new system approach (and for +resources whose initialization depends on a Bevy core resource, it may be required). In fact, we +encourage users to abandon `Plugin::finish` entirely and move all their system and resource +initializations for rendering into `Plugin::build` instead. + +As stated before, we've ported many resources to be initialized in `RenderStartup`. See the +migration guide for a full list of affected resources. diff --git a/release-content/release-notes/scene-type-crates.md b/release-content/release-notes/scene-type-crates.md new file mode 100644 index 0000000000..875c2a5e92 --- /dev/null +++ b/release-content/release-notes/scene-type-crates.md @@ -0,0 +1,7 @@ +--- +title: Define scenes without depending on bevy_render +authors: ["@atlv24"] +pull_requests: [19997, 19991, 20000, 19949, 19943, 19953] +--- + +It is now possible to use cameras, lights, and meshes without depending on the Bevy renderer. This makes it possible for 3rd party custom renderers to be drop-in replacements for rendering existing scenes.