304 lines
12 KiB
Rust
304 lines
12 KiB
Rust
//! Types for handling [`Bundle`]s.
|
|
//!
|
|
//! This module contains the [`Bundle`] trait and some other helper types.
|
|
|
|
mod impls;
|
|
mod info;
|
|
mod insert;
|
|
mod remove;
|
|
mod spawner;
|
|
#[cfg(test)]
|
|
mod tests;
|
|
|
|
pub(crate) use insert::BundleInserter;
|
|
pub(crate) use remove::BundleRemover;
|
|
pub(crate) use spawner::BundleSpawner;
|
|
|
|
pub use info::*;
|
|
|
|
/// Derive the [`Bundle`] trait
|
|
///
|
|
/// You can apply this derive macro to structs that are
|
|
/// composed of [`Component`](crate::component::Component)s or
|
|
/// other [`Bundle`]s.
|
|
///
|
|
/// ## Attributes
|
|
///
|
|
/// Sometimes parts of the Bundle should not be inserted.
|
|
/// Those can be marked with `#[bundle(ignore)]`, and they will be skipped.
|
|
/// In that case, the field needs to implement [`Default`] unless you also ignore
|
|
/// the [`BundleFromComponents`] implementation.
|
|
///
|
|
/// ```rust
|
|
/// # use bevy_ecs::prelude::{Component, Bundle};
|
|
/// # #[derive(Component)]
|
|
/// # struct Hitpoint;
|
|
/// #
|
|
/// #[derive(Bundle)]
|
|
/// struct HitpointMarker {
|
|
/// hitpoints: Hitpoint,
|
|
///
|
|
/// #[bundle(ignore)]
|
|
/// creator: Option<String>
|
|
/// }
|
|
/// ```
|
|
///
|
|
/// Some fields may be bundles that do not implement
|
|
/// [`BundleFromComponents`]. This happens for bundles that cannot be extracted.
|
|
/// For example with [`SpawnRelatedBundle`](bevy_ecs::spawn::SpawnRelatedBundle), see below for an
|
|
/// example usage.
|
|
/// In those cases you can either ignore it as above,
|
|
/// or you can opt out the whole Struct by marking it as ignored with
|
|
/// `#[bundle(ignore_from_components)]`.
|
|
///
|
|
/// ```rust
|
|
/// # use bevy_ecs::prelude::{Component, Bundle, ChildOf, Spawn};
|
|
/// # #[derive(Component)]
|
|
/// # struct Hitpoint;
|
|
/// # #[derive(Component)]
|
|
/// # struct Marker;
|
|
/// #
|
|
/// use bevy_ecs::spawn::SpawnRelatedBundle;
|
|
///
|
|
/// #[derive(Bundle)]
|
|
/// #[bundle(ignore_from_components)]
|
|
/// struct HitpointMarker {
|
|
/// hitpoints: Hitpoint,
|
|
/// related_spawner: SpawnRelatedBundle<ChildOf, Spawn<Marker>>,
|
|
/// }
|
|
/// ```
|
|
pub use bevy_ecs_macros::Bundle;
|
|
|
|
use crate::{
|
|
component::{ComponentId, Components, ComponentsRegistrator, StorageType},
|
|
world::EntityWorldMut,
|
|
};
|
|
use bevy_ptr::OwningPtr;
|
|
|
|
/// A collection of components, whose identity may or may not be fixed at compile time.
|
|
///
|
|
/// The `Bundle` trait enables insertion of [`Component`]s to an entity.
|
|
/// For the removal of [`Component`]s from an entity see the [`StaticBundle`]`trait`.
|
|
///
|
|
/// Implementers of the `Bundle` trait are called 'bundles'.
|
|
///
|
|
/// Currently, bundles can only contain one of each [`Component`], and will
|
|
/// panic once initialized if this is not met.
|
|
///
|
|
/// ## Insertion
|
|
///
|
|
/// The primary use for bundles is to add a useful collection of components to an entity.
|
|
///
|
|
/// Adding a value of bundle to an entity will add the components from the set it
|
|
/// represents to the entity.
|
|
/// The values of these components are taken from the bundle.
|
|
/// If an entity already had one of these components, the entity's original component value
|
|
/// will be overwritten.
|
|
///
|
|
/// Importantly, bundles are only their constituent set of components.
|
|
/// You **should not** use bundles as a unit of behavior.
|
|
/// The behavior of your app can only be considered in terms of components, as systems,
|
|
/// which drive the behavior of a `bevy` application, operate on combinations of
|
|
/// components.
|
|
///
|
|
/// This rule is also important because multiple bundles may contain the same component type,
|
|
/// calculated in different ways — adding both of these bundles to one entity
|
|
/// would create incoherent behavior.
|
|
/// This would be unexpected if bundles were treated as an abstraction boundary, as
|
|
/// the abstraction would be unmaintainable for these cases.
|
|
///
|
|
/// For this reason, there is intentionally no [`Query`] to match whether an entity
|
|
/// contains the components of a bundle.
|
|
/// Queries should instead only select the components they logically operate on.
|
|
///
|
|
/// # Implementers
|
|
///
|
|
/// Every type which implements [`Component`] also implements `Bundle`, since
|
|
/// [`Component`] types can be added to or removed from an entity.
|
|
///
|
|
/// Additionally, [Tuples](`tuple`) of bundles are also [`Bundle`] (with up to 15 bundles).
|
|
/// These bundles contain the items of the 'inner' bundles.
|
|
/// This is a convenient shorthand which is primarily used when spawning entities.
|
|
///
|
|
/// [`unit`], otherwise known as [`()`](`unit`), is a [`Bundle`] containing no components (since it
|
|
/// can also be considered as the empty tuple).
|
|
/// This can be useful for spawning large numbers of empty entities using
|
|
/// [`World::spawn_batch`](crate::world::World::spawn_batch).
|
|
///
|
|
/// Tuple bundles can be nested, which can be used to create an anonymous bundle with more than
|
|
/// 15 items.
|
|
/// However, in most cases where this is required, the derive macro [`derive@Bundle`] should be
|
|
/// used instead.
|
|
/// The derived `Bundle` implementation contains the items of its fields, which all must
|
|
/// implement `Bundle`.
|
|
/// As explained above, this includes any [`Component`] type, and other derived bundles.
|
|
///
|
|
/// If you want to add `PhantomData` to your `Bundle` you have to mark it with `#[bundle(ignore)]`.
|
|
/// ```
|
|
/// # use std::marker::PhantomData;
|
|
/// use bevy_ecs::{component::Component, bundle::Bundle};
|
|
///
|
|
/// #[derive(Component)]
|
|
/// struct XPosition(i32);
|
|
/// #[derive(Component)]
|
|
/// struct YPosition(i32);
|
|
///
|
|
/// #[derive(Bundle)]
|
|
/// struct PositionBundle {
|
|
/// // A bundle can contain components
|
|
/// x: XPosition,
|
|
/// y: YPosition,
|
|
/// }
|
|
///
|
|
/// // You have to implement `Default` for ignored field types in bundle structs.
|
|
/// #[derive(Default)]
|
|
/// struct Other(f32);
|
|
///
|
|
/// #[derive(Bundle)]
|
|
/// struct NamedPointBundle<T: Send + Sync + 'static> {
|
|
/// // Or other bundles
|
|
/// a: PositionBundle,
|
|
/// // In addition to more components
|
|
/// z: PointName,
|
|
///
|
|
/// // when you need to use `PhantomData` you have to mark it as ignored
|
|
/// #[bundle(ignore)]
|
|
/// _phantom_data: PhantomData<T>
|
|
/// }
|
|
///
|
|
/// #[derive(Component)]
|
|
/// struct PointName(String);
|
|
/// ```
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// Manual implementations of this trait are unsupported.
|
|
/// That is, there is no safe way to implement this trait, and you must not do so.
|
|
/// If you want a type to implement [`Bundle`], you must use [`derive@Bundle`](derive@Bundle).
|
|
///
|
|
/// [`Component`]: crate::component::Component
|
|
/// [`Query`]: crate::system::Query
|
|
// Some safety points:
|
|
// - [`Bundle::component_ids`] must return the [`ComponentId`] for each component type in the
|
|
// bundle, in the _exact_ order that [`DynamicBundle::get_components`] is called.
|
|
// - [`Bundle::from_components`] must call `func` exactly once for each [`ComponentId`] returned by
|
|
// [`Bundle::component_ids`].
|
|
// - [`Bundle::component_ids`], [`Bundle::get_component_ids`] and [`Bundle::register_required_components`]
|
|
// cannot depend on `self` for now.
|
|
#[diagnostic::on_unimplemented(
|
|
message = "`{Self}` is not a `Bundle`",
|
|
label = "invalid `Bundle`",
|
|
note = "consider annotating `{Self}` with `#[derive(Component)]` or `#[derive(Bundle)]`"
|
|
)]
|
|
pub unsafe trait Bundle: DynamicBundle + Send + Sync + 'static {
|
|
/// Gets this [`Bundle`]'s component ids, in the order of this bundle's [`Component`](crate::component::Component)s
|
|
fn component_ids(
|
|
&self,
|
|
components: &mut ComponentsRegistrator,
|
|
ids: &mut impl FnMut(ComponentId),
|
|
);
|
|
|
|
/// Gets this [`Bundle`]'s component ids. This will be [`None`] if the component has not been registered.
|
|
fn get_component_ids(&self, components: &Components, ids: &mut impl FnMut(Option<ComponentId>));
|
|
}
|
|
|
|
/// A static and fixed set of [`Component`] types.
|
|
/// See the [`Bundle`] trait for a possibly dynamic set of [`Component`] types.
|
|
///
|
|
/// Implementers of the [`StaticBundle`] trait are called 'static bundles'.
|
|
///
|
|
/// ## Removal
|
|
///
|
|
/// Static bundles are used when removing components from an entity.
|
|
///
|
|
/// Removing a bundle from an entity will remove any of its components attached
|
|
/// to the entity from the entity.
|
|
/// That is, if the entity does not have all the components of the bundle, those
|
|
/// which are present will be removed.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// Manual implementations of this trait are unsupported.
|
|
/// That is, there is no safe way to implement this trait, and you must not do so.
|
|
/// If you want a type to implement [`StaticBundle`], you must use [`derive@Bundle`](derive@Bundle).
|
|
///
|
|
/// [`Component`]: crate::component::Component
|
|
//
|
|
// (bevy internal doc) Some safety points:
|
|
// - [`StaticBundle::component_ids`] and [`StaticBundle::get_component_ids`] must match the behavior of [`Bundle::component_ids`]
|
|
#[diagnostic::on_unimplemented(
|
|
message = "`{Self}` is not a `StaticBundle`",
|
|
label = "invalid `StaticBundle`",
|
|
note = "consider annotating `{Self}` with `#[derive(Component)]` or `#[derive(Bundle)]`"
|
|
)]
|
|
pub unsafe trait StaticBundle: Send + Sync + 'static {
|
|
/// Gets this [`StaticBundle`]'s component ids, in the order of this bundle's [`Component`]s
|
|
#[doc(hidden)]
|
|
fn component_ids(components: &mut ComponentsRegistrator, ids: &mut impl FnMut(ComponentId));
|
|
|
|
/// Gets this [`StaticBundle`]'s component ids. This will be [`None`] if the component has not been registered.
|
|
#[doc(hidden)]
|
|
fn get_component_ids(components: &Components, ids: &mut impl FnMut(Option<ComponentId>));
|
|
}
|
|
|
|
/// Creates a bundle by taking it from the internal storage.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// Manual implementations of this trait are unsupported.
|
|
/// That is, there is no safe way to implement this trait, and you must not do so.
|
|
/// If you want a type to implement [`Bundle`], you must use [`derive@Bundle`](derive@Bundle).
|
|
///
|
|
/// [`Query`]: crate::system::Query
|
|
// Some safety points:
|
|
// - [`Bundle::component_ids`] must return the [`ComponentId`] for each component type in the
|
|
// bundle, in the _exact_ order that [`DynamicBundle::get_components`] is called.
|
|
// - [`Bundle::from_components`] must call `func` exactly once for each [`ComponentId`] returned by
|
|
// [`Bundle::component_ids`].
|
|
pub unsafe trait BundleFromComponents {
|
|
/// Calls `func`, which should return data for each component in the bundle, in the order of
|
|
/// this bundle's [`Component`]s
|
|
///
|
|
/// # Safety
|
|
/// Caller must return data for each component in the bundle, in the order of this bundle's
|
|
/// [`Component`]s
|
|
#[doc(hidden)]
|
|
unsafe fn from_components<T, F>(ctx: &mut T, func: &mut F) -> Self
|
|
where
|
|
// Ensure that the `OwningPtr` is used correctly
|
|
F: for<'a> FnMut(&'a mut T) -> OwningPtr<'a>,
|
|
Self: Sized;
|
|
}
|
|
|
|
/// The parts from [`Bundle`] that don't require statically knowing the components of the bundle.
|
|
pub trait DynamicBundle {
|
|
/// An operation on the entity that happens _after_ inserting this bundle.
|
|
type Effect: BundleEffect;
|
|
// SAFETY:
|
|
// The `StorageType` argument passed into [`Bundle::get_components`] must be correct for the
|
|
// component being fetched.
|
|
//
|
|
/// Calls `func` on each value, in the order of this bundle's [`Component`]s. This passes
|
|
/// ownership of the component values to `func`.
|
|
#[doc(hidden)]
|
|
fn get_components(self, func: &mut impl FnMut(StorageType, OwningPtr<'_>)) -> Self::Effect;
|
|
}
|
|
|
|
/// An operation on an [`Entity`](crate::entity::Entity) that occurs _after_ inserting the
|
|
/// [`Bundle`] that defined this bundle effect.
|
|
/// The order of operations is:
|
|
///
|
|
/// 1. The [`Bundle`] is inserted on the entity
|
|
/// 2. Relevant Hooks are run for the insert, then Observers
|
|
/// 3. The [`BundleEffect`] is run.
|
|
///
|
|
/// See [`DynamicBundle::Effect`].
|
|
pub trait BundleEffect {
|
|
/// Applies this effect to the given `entity`.
|
|
fn apply(self, entity: &mut EntityWorldMut);
|
|
}
|
|
|
|
/// A trait implemented for [`BundleEffect`] implementations that do nothing. This is used as a type constraint for
|
|
/// [`Bundle`] APIs that do not / cannot run [`DynamicBundle::Effect`], such as "batch spawn" APIs.
|
|
pub trait NoBundleEffect {}
|