Merge 0309198315 into 877d278785
This commit is contained in:
commit
6b51be74d8
@ -1,7 +1,7 @@
|
|||||||
use core::hint::black_box;
|
use core::hint::black_box;
|
||||||
|
|
||||||
use benches::bench;
|
use benches::bench;
|
||||||
use bevy_ecs::bundle::{Bundle, InsertMode};
|
use bevy_ecs::bundle::{Bundle, InsertMode, StaticBundle};
|
||||||
use bevy_ecs::component::ComponentCloneBehavior;
|
use bevy_ecs::component::ComponentCloneBehavior;
|
||||||
use bevy_ecs::entity::EntityCloner;
|
use bevy_ecs::entity::EntityCloner;
|
||||||
use bevy_ecs::hierarchy::ChildOf;
|
use bevy_ecs::hierarchy::ChildOf;
|
||||||
@ -27,7 +27,7 @@ type ComplexBundle = (C<1>, C<2>, C<3>, C<4>, C<5>, C<6>, C<7>, C<8>, C<9>, C<10
|
|||||||
|
|
||||||
/// Sets the [`ComponentCloneBehavior`] for all explicit and required components in a bundle `B` to
|
/// Sets the [`ComponentCloneBehavior`] for all explicit and required components in a bundle `B` to
|
||||||
/// use the [`Reflect`] trait instead of [`Clone`].
|
/// use the [`Reflect`] trait instead of [`Clone`].
|
||||||
fn reflection_cloner<B: Bundle + GetTypeRegistration>(
|
fn reflection_cloner<B: StaticBundle + GetTypeRegistration>(
|
||||||
world: &mut World,
|
world: &mut World,
|
||||||
linked_cloning: bool,
|
linked_cloning: bool,
|
||||||
) -> EntityCloner {
|
) -> EntityCloner {
|
||||||
@ -65,7 +65,7 @@ fn reflection_cloner<B: Bundle + GetTypeRegistration>(
|
|||||||
/// components (which is usually [`ComponentCloneBehavior::clone()`]). If `clone_via_reflect`
|
/// components (which is usually [`ComponentCloneBehavior::clone()`]). If `clone_via_reflect`
|
||||||
/// is true, it will overwrite the handler for all components in the bundle to be
|
/// is true, it will overwrite the handler for all components in the bundle to be
|
||||||
/// [`ComponentCloneBehavior::reflect()`].
|
/// [`ComponentCloneBehavior::reflect()`].
|
||||||
fn bench_clone<B: Bundle + Default + GetTypeRegistration>(
|
fn bench_clone<B: Bundle + StaticBundle + Default + GetTypeRegistration>(
|
||||||
b: &mut Bencher,
|
b: &mut Bencher,
|
||||||
clone_via_reflect: bool,
|
clone_via_reflect: bool,
|
||||||
) {
|
) {
|
||||||
@ -96,7 +96,7 @@ fn bench_clone<B: Bundle + Default + GetTypeRegistration>(
|
|||||||
/// For example, setting `height` to 5 and `children` to 1 creates a single chain of entities with
|
/// For example, setting `height` to 5 and `children` to 1 creates a single chain of entities with
|
||||||
/// no siblings. Alternatively, setting `height` to 1 and `children` to 5 will spawn 5 direct
|
/// no siblings. Alternatively, setting `height` to 1 and `children` to 5 will spawn 5 direct
|
||||||
/// children of the root entity.
|
/// children of the root entity.
|
||||||
fn bench_clone_hierarchy<B: Bundle + Default + GetTypeRegistration>(
|
fn bench_clone_hierarchy<B: Bundle + StaticBundle + Default + GetTypeRegistration>(
|
||||||
b: &mut Bencher,
|
b: &mut Bencher,
|
||||||
height: usize,
|
height: usize,
|
||||||
children: usize,
|
children: usize,
|
||||||
@ -268,7 +268,7 @@ const FILTER_SCENARIOS: [FilterScenario; 11] = [
|
|||||||
///
|
///
|
||||||
/// The bundle must implement [`Default`], which is used to create the first entity that gets its components cloned
|
/// The bundle must implement [`Default`], which is used to create the first entity that gets its components cloned
|
||||||
/// in the benchmark. It may also be used to populate the target entity depending on the scenario.
|
/// in the benchmark. It may also be used to populate the target entity depending on the scenario.
|
||||||
fn bench_filter<B: Bundle + Default>(b: &mut Bencher, scenario: FilterScenario) {
|
fn bench_filter<B: Bundle + StaticBundle + Default>(b: &mut Bencher, scenario: FilterScenario) {
|
||||||
let mut world = World::default();
|
let mut world = World::default();
|
||||||
let mut spawn = |empty| match empty {
|
let mut spawn = |empty| match empty {
|
||||||
false => world.spawn(B::default()).id(),
|
false => world.spawn(B::default()).id(),
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use core::hint::black_box;
|
|||||||
use nonmax::NonMaxU32;
|
use nonmax::NonMaxU32;
|
||||||
|
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
bundle::{Bundle, NoBundleEffect},
|
bundle::{Bundle, NoBundleEffect, StaticBundle},
|
||||||
component::Component,
|
component::Component,
|
||||||
entity::{Entity, EntityRow},
|
entity::{Entity, EntityRow},
|
||||||
system::{Query, SystemState},
|
system::{Query, SystemState},
|
||||||
@ -37,7 +37,9 @@ fn setup<T: Component + Default>(entity_count: u32) -> World {
|
|||||||
black_box(world)
|
black_box(world)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_wide<T: Bundle<Effect: NoBundleEffect> + Default>(entity_count: u32) -> World {
|
fn setup_wide<T: Bundle<Effect: NoBundleEffect> + StaticBundle + Default>(
|
||||||
|
entity_count: u32,
|
||||||
|
) -> World {
|
||||||
let mut world = World::default();
|
let mut world = World::default();
|
||||||
world.spawn_batch((0..entity_count).map(|_| T::default()));
|
world.spawn_batch((0..entity_count).map(|_| T::default()));
|
||||||
black_box(world)
|
black_box(world)
|
||||||
|
|||||||
@ -9,6 +9,7 @@ use alloc::{
|
|||||||
};
|
};
|
||||||
pub use bevy_derive::AppLabel;
|
pub use bevy_derive::AppLabel;
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
|
bundle::StaticBundle,
|
||||||
component::RequiredComponentsError,
|
component::RequiredComponentsError,
|
||||||
error::{DefaultErrorHandler, ErrorHandler},
|
error::{DefaultErrorHandler, ErrorHandler},
|
||||||
event::{event_update_system, EventCursor},
|
event::{event_update_system, EventCursor},
|
||||||
@ -1340,7 +1341,7 @@ impl App {
|
|||||||
/// }
|
/// }
|
||||||
/// });
|
/// });
|
||||||
/// ```
|
/// ```
|
||||||
pub fn add_observer<E: Event, B: Bundle, M>(
|
pub fn add_observer<E: Event, B: StaticBundle, M>(
|
||||||
&mut self,
|
&mut self,
|
||||||
observer: impl IntoObserverSystem<E, B, M>,
|
observer: impl IntoObserverSystem<E, B, M>,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
|
|||||||
@ -28,18 +28,21 @@ enum BundleFieldKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const BUNDLE_ATTRIBUTE_NAME: &str = "bundle";
|
const BUNDLE_ATTRIBUTE_NAME: &str = "bundle";
|
||||||
|
const BUNDLE_ATTRIBUTE_DYNAMIC: &str = "dynamic";
|
||||||
const BUNDLE_ATTRIBUTE_IGNORE_NAME: &str = "ignore";
|
const BUNDLE_ATTRIBUTE_IGNORE_NAME: &str = "ignore";
|
||||||
const BUNDLE_ATTRIBUTE_NO_FROM_COMPONENTS: &str = "ignore_from_components";
|
const BUNDLE_ATTRIBUTE_NO_FROM_COMPONENTS: &str = "ignore_from_components";
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct BundleAttributes {
|
struct BundleAttributes {
|
||||||
impl_from_components: bool,
|
impl_from_components: bool,
|
||||||
|
dynamic: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for BundleAttributes {
|
impl Default for BundleAttributes {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
impl_from_components: true,
|
impl_from_components: true,
|
||||||
|
dynamic: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,8 +64,12 @@ pub fn derive_bundle(input: TokenStream) -> TokenStream {
|
|||||||
attributes.impl_from_components = false;
|
attributes.impl_from_components = false;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
if meta.path.is_ident(BUNDLE_ATTRIBUTE_DYNAMIC) {
|
||||||
|
attributes.dynamic = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
Err(meta.error(format!("Invalid bundle container attribute. Allowed attributes: `{BUNDLE_ATTRIBUTE_NO_FROM_COMPONENTS}`")))
|
Err(meta.error(format!("Invalid bundle container attribute. Allowed attributes: `{BUNDLE_ATTRIBUTE_NO_FROM_COMPONENTS}`, `{BUNDLE_ATTRIBUTE_DYNAMIC}`")))
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Err(error) = parsing {
|
if let Err(error) = parsing {
|
||||||
@ -139,6 +146,30 @@ pub fn derive_bundle(input: TokenStream) -> TokenStream {
|
|||||||
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
||||||
let struct_name = &ast.ident;
|
let struct_name = &ast.ident;
|
||||||
|
|
||||||
|
let static_bundle_impl = (!attributes.dynamic).then(|| quote! {
|
||||||
|
// SAFETY:
|
||||||
|
// - all the active fields must implement `StaticBundle` for the function bodies to compile, and hence
|
||||||
|
// this bundle also represents a static set of components;
|
||||||
|
// - `component_ids` and `get_component_ids` delegate to the underlying implementation in the same order
|
||||||
|
// and hence are coherent;
|
||||||
|
#[allow(deprecated)]
|
||||||
|
unsafe impl #impl_generics #ecs_path::bundle::StaticBundle for #struct_name #ty_generics #where_clause {
|
||||||
|
fn component_ids(
|
||||||
|
components: &mut #ecs_path::component::ComponentsRegistrator,
|
||||||
|
ids: &mut impl FnMut(#ecs_path::component::ComponentId)
|
||||||
|
){
|
||||||
|
#(<#active_field_types as #ecs_path::bundle::StaticBundle>::component_ids(components, &mut *ids);)*
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_component_ids(
|
||||||
|
components: &#ecs_path::component::Components,
|
||||||
|
ids: &mut impl FnMut(Option<#ecs_path::component::ComponentId>)
|
||||||
|
){
|
||||||
|
#(<#active_field_types as #ecs_path::bundle::StaticBundle>::get_component_ids(components, &mut *ids);)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let bundle_impl = quote! {
|
let bundle_impl = quote! {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - ComponentId is returned in field-definition-order. [get_components] uses field-definition-order
|
// - ComponentId is returned in field-definition-order. [get_components] uses field-definition-order
|
||||||
@ -147,17 +178,19 @@ pub fn derive_bundle(input: TokenStream) -> TokenStream {
|
|||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
unsafe impl #impl_generics #ecs_path::bundle::Bundle for #struct_name #ty_generics #where_clause {
|
unsafe impl #impl_generics #ecs_path::bundle::Bundle for #struct_name #ty_generics #where_clause {
|
||||||
fn component_ids(
|
fn component_ids(
|
||||||
|
&self,
|
||||||
components: &mut #ecs_path::component::ComponentsRegistrator,
|
components: &mut #ecs_path::component::ComponentsRegistrator,
|
||||||
ids: &mut impl FnMut(#ecs_path::component::ComponentId)
|
ids: &mut impl FnMut(#ecs_path::component::ComponentId)
|
||||||
) {
|
) {
|
||||||
#(<#active_field_types as #ecs_path::bundle::Bundle>::component_ids(components, ids);)*
|
#(<#active_field_types as #ecs_path::bundle::Bundle>::component_ids(&self.#active_field_tokens, components, ids);)*
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_component_ids(
|
fn get_component_ids(
|
||||||
|
&self,
|
||||||
components: &#ecs_path::component::Components,
|
components: &#ecs_path::component::Components,
|
||||||
ids: &mut impl FnMut(Option<#ecs_path::component::ComponentId>)
|
ids: &mut impl FnMut(Option<#ecs_path::component::ComponentId>)
|
||||||
) {
|
) {
|
||||||
#(<#active_field_types as #ecs_path::bundle::Bundle>::get_component_ids(components, &mut *ids);)*
|
#(<#active_field_types as #ecs_path::bundle::Bundle>::get_component_ids(&self.#active_field_tokens, components, &mut *ids);)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -177,7 +210,7 @@ pub fn derive_bundle(input: TokenStream) -> TokenStream {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let from_components_impl = attributes.impl_from_components.then(|| quote! {
|
let from_components_impl = (attributes.impl_from_components && !attributes.dynamic).then(|| quote! {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - ComponentId is returned in field-definition-order. [from_components] uses field-definition-order
|
// - ComponentId is returned in field-definition-order. [from_components] uses field-definition-order
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
@ -199,6 +232,7 @@ pub fn derive_bundle(input: TokenStream) -> TokenStream {
|
|||||||
|
|
||||||
TokenStream::from(quote! {
|
TokenStream::from(quote! {
|
||||||
#(#attribute_errors)*
|
#(#attribute_errors)*
|
||||||
|
#static_bundle_impl
|
||||||
#bundle_impl
|
#bundle_impl
|
||||||
#from_components_impl
|
#from_components_impl
|
||||||
#dynamic_bundle_impl
|
#dynamic_bundle_impl
|
||||||
|
|||||||
@ -4,15 +4,17 @@ use bevy_ptr::OwningPtr;
|
|||||||
use variadics_please::all_tuples;
|
use variadics_please::all_tuples;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bundle::{Bundle, BundleEffect, BundleFromComponents, DynamicBundle, NoBundleEffect},
|
bundle::{
|
||||||
|
Bundle, BundleEffect, BundleFromComponents, DynamicBundle, NoBundleEffect, StaticBundle,
|
||||||
|
},
|
||||||
component::{Component, ComponentId, Components, ComponentsRegistrator, StorageType},
|
component::{Component, ComponentId, Components, ComponentsRegistrator, StorageType},
|
||||||
world::EntityWorldMut,
|
world::EntityWorldMut,
|
||||||
};
|
};
|
||||||
|
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - `Bundle::component_ids` calls `ids` for C's component id (and nothing else)
|
// - `C` always represents the set of components containing just `C`
|
||||||
// - `Bundle::get_components` is called exactly once for C and passes the component's storage type based on its associated constant.
|
// - `component_ids` and `get_component_ids` both call `ids` just once for C's component id (and nothing else).
|
||||||
unsafe impl<C: Component> Bundle for C {
|
unsafe impl<C: Component> StaticBundle for C {
|
||||||
fn component_ids(components: &mut ComponentsRegistrator, ids: &mut impl FnMut(ComponentId)) {
|
fn component_ids(components: &mut ComponentsRegistrator, ids: &mut impl FnMut(ComponentId)) {
|
||||||
ids(components.register_component::<C>());
|
ids(components.register_component::<C>());
|
||||||
}
|
}
|
||||||
@ -22,6 +24,27 @@ unsafe impl<C: Component> Bundle for C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SAFETY:
|
||||||
|
// - `component_ids` calls `ids` for C's component id (and nothing else)
|
||||||
|
// - `get_components` is called exactly once for C and passes the component's storage type based on its associated constant.
|
||||||
|
unsafe impl<C: Component> Bundle for C {
|
||||||
|
fn component_ids(
|
||||||
|
&self,
|
||||||
|
components: &mut ComponentsRegistrator,
|
||||||
|
ids: &mut impl FnMut(ComponentId),
|
||||||
|
) {
|
||||||
|
<Self as StaticBundle>::component_ids(components, ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_component_ids(
|
||||||
|
&self,
|
||||||
|
components: &Components,
|
||||||
|
ids: &mut impl FnMut(Option<ComponentId>),
|
||||||
|
) {
|
||||||
|
<Self as StaticBundle>::get_component_ids(components, ids);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - `Bundle::from_components` calls `func` exactly once for C, which is the exact value returned by `Bundle::component_ids`.
|
// - `Bundle::from_components` calls `func` exactly once for C, which is the exact value returned by `Bundle::component_ids`.
|
||||||
unsafe impl<C: Component> BundleFromComponents for C {
|
unsafe impl<C: Component> BundleFromComponents for C {
|
||||||
@ -47,6 +70,30 @@ impl<C: Component> DynamicBundle for C {
|
|||||||
|
|
||||||
macro_rules! tuple_impl {
|
macro_rules! tuple_impl {
|
||||||
($(#[$meta:meta])* $($name: ident),*) => {
|
($(#[$meta:meta])* $($name: ident),*) => {
|
||||||
|
#[expect(
|
||||||
|
clippy::allow_attributes,
|
||||||
|
reason = "This is a tuple-related macro; as such, the lints below may not always apply."
|
||||||
|
)]
|
||||||
|
#[allow(
|
||||||
|
unused_mut,
|
||||||
|
unused_variables,
|
||||||
|
reason = "Zero-length tuples won't use any of the parameters."
|
||||||
|
)]
|
||||||
|
$(#[$meta])*
|
||||||
|
// SAFETY:
|
||||||
|
// - all the sub-bundles are static, and hence their combination is static too;
|
||||||
|
// - `component_ids` and `get_component_ids` both delegate to the sub-bundle's methods
|
||||||
|
// exactly once per sub-bundle, hence they are coherent.
|
||||||
|
unsafe impl<$($name: StaticBundle),*> StaticBundle for ($($name,)*) {
|
||||||
|
fn component_ids(components: &mut ComponentsRegistrator, ids: &mut impl FnMut(ComponentId)){
|
||||||
|
$(<$name as StaticBundle>::component_ids(components, ids);)*
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_component_ids(components: &Components, ids: &mut impl FnMut(Option<ComponentId>)){
|
||||||
|
$(<$name as StaticBundle>::get_component_ids(components, ids);)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[expect(
|
#[expect(
|
||||||
clippy::allow_attributes,
|
clippy::allow_attributes,
|
||||||
reason = "This is a tuple-related macro; as such, the lints below may not always apply."
|
reason = "This is a tuple-related macro; as such, the lints below may not always apply."
|
||||||
@ -64,12 +111,24 @@ macro_rules! tuple_impl {
|
|||||||
// - `Bundle::get_components` is called exactly once for each member. Relies on the above implementation to pass the correct
|
// - `Bundle::get_components` is called exactly once for each member. Relies on the above implementation to pass the correct
|
||||||
// `StorageType` into the callback.
|
// `StorageType` into the callback.
|
||||||
unsafe impl<$($name: Bundle),*> Bundle for ($($name,)*) {
|
unsafe impl<$($name: Bundle),*> Bundle for ($($name,)*) {
|
||||||
fn component_ids(components: &mut ComponentsRegistrator, ids: &mut impl FnMut(ComponentId)){
|
fn component_ids(&self, components: &mut ComponentsRegistrator, ids: &mut impl FnMut(ComponentId)){
|
||||||
$(<$name as Bundle>::component_ids(components, ids);)*
|
#[allow(
|
||||||
|
non_snake_case,
|
||||||
|
reason = "The names of these variables are provided by the caller, not by us."
|
||||||
|
)]
|
||||||
|
let ($($name,)*) = self;
|
||||||
|
|
||||||
|
$(<$name as Bundle>::component_ids($name, components, ids);)*
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_component_ids(components: &Components, ids: &mut impl FnMut(Option<ComponentId>)){
|
fn get_component_ids(&self, components: &Components, ids: &mut impl FnMut(Option<ComponentId>)){
|
||||||
$(<$name as Bundle>::get_component_ids(components, ids);)*
|
#[allow(
|
||||||
|
non_snake_case,
|
||||||
|
reason = "The names of these variables are provided by the caller, not by us."
|
||||||
|
)]
|
||||||
|
let ($($name,)*) = self;
|
||||||
|
|
||||||
|
$(<$name as Bundle>::get_component_ids($name, components, ids);)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use core::{any::TypeId, ptr::NonNull};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
archetype::{Archetype, BundleComponentStatus, ComponentStatus},
|
archetype::{Archetype, BundleComponentStatus, ComponentStatus},
|
||||||
bundle::{Bundle, DynamicBundle},
|
bundle::{Bundle, DynamicBundle, StaticBundle},
|
||||||
change_detection::MaybeLocation,
|
change_detection::MaybeLocation,
|
||||||
component::{
|
component::{
|
||||||
ComponentId, Components, ComponentsRegistrator, RequiredComponentConstructor,
|
ComponentId, Components, ComponentsRegistrator, RequiredComponentConstructor,
|
||||||
@ -401,10 +401,7 @@ impl Bundles {
|
|||||||
self.bundle_ids.get(&type_id).cloned()
|
self.bundle_ids.get(&type_id).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers a new [`BundleInfo`] for a statically known type.
|
pub(crate) fn register_static_info<T: StaticBundle>(
|
||||||
///
|
|
||||||
/// Also registers all the components in the bundle.
|
|
||||||
pub(crate) fn register_info<T: Bundle>(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
components: &mut ComponentsRegistrator,
|
components: &mut ComponentsRegistrator,
|
||||||
storages: &mut Storages,
|
storages: &mut Storages,
|
||||||
@ -425,10 +422,35 @@ impl Bundles {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Registers a new [`BundleInfo`] for a statically known type.
|
||||||
|
///
|
||||||
|
/// Also registers all the components in the bundle.
|
||||||
|
pub(crate) fn register_info<T: Bundle>(
|
||||||
|
&mut self,
|
||||||
|
bundle: &T,
|
||||||
|
components: &mut ComponentsRegistrator,
|
||||||
|
storages: &mut Storages,
|
||||||
|
) -> BundleId {
|
||||||
|
let bundle_infos = &mut self.bundle_infos;
|
||||||
|
*self.bundle_ids.entry(TypeId::of::<T>()).or_insert_with(|| {
|
||||||
|
let mut component_ids= Vec::new();
|
||||||
|
bundle.component_ids(components, &mut |id| component_ids.push(id));
|
||||||
|
let id = BundleId(bundle_infos.len());
|
||||||
|
let bundle_info =
|
||||||
|
// SAFETY: T::component_id ensures:
|
||||||
|
// - its info was created
|
||||||
|
// - appropriate storage for it has been initialized.
|
||||||
|
// - it was created in the same order as the components in T
|
||||||
|
unsafe { BundleInfo::new(core::any::type_name::<T>(), storages, components, component_ids, id) };
|
||||||
|
bundle_infos.push(bundle_info);
|
||||||
|
id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Registers a new [`BundleInfo`], which contains both explicit and required components for a statically known type.
|
/// Registers a new [`BundleInfo`], which contains both explicit and required components for a statically known type.
|
||||||
///
|
///
|
||||||
/// Also registers all the components in the bundle.
|
/// Also registers all the components in the bundle.
|
||||||
pub(crate) fn register_contributed_bundle_info<T: Bundle>(
|
pub(crate) fn register_contributed_bundle_info<T: StaticBundle>(
|
||||||
&mut self,
|
&mut self,
|
||||||
components: &mut ComponentsRegistrator,
|
components: &mut ComponentsRegistrator,
|
||||||
storages: &mut Storages,
|
storages: &mut Storages,
|
||||||
@ -436,7 +458,7 @@ impl Bundles {
|
|||||||
if let Some(id) = self.contributed_bundle_ids.get(&TypeId::of::<T>()).cloned() {
|
if let Some(id) = self.contributed_bundle_ids.get(&TypeId::of::<T>()).cloned() {
|
||||||
id
|
id
|
||||||
} else {
|
} else {
|
||||||
let explicit_bundle_id = self.register_info::<T>(components, storages);
|
let explicit_bundle_id = self.register_static_info::<T>(components, storages);
|
||||||
// SAFETY: reading from `explicit_bundle_id` and creating new bundle in same time. Its valid because bundle hashmap allow this
|
// SAFETY: reading from `explicit_bundle_id` and creating new bundle in same time. Its valid because bundle hashmap allow this
|
||||||
let id = unsafe {
|
let id = unsafe {
|
||||||
let (ptr, len) = {
|
let (ptr, len) = {
|
||||||
|
|||||||
@ -33,6 +33,7 @@ pub(crate) struct BundleInserter<'w> {
|
|||||||
impl<'w> BundleInserter<'w> {
|
impl<'w> BundleInserter<'w> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn new<T: Bundle>(
|
pub(crate) fn new<T: Bundle>(
|
||||||
|
bundle: &T,
|
||||||
world: &'w mut World,
|
world: &'w mut World,
|
||||||
archetype_id: ArchetypeId,
|
archetype_id: ArchetypeId,
|
||||||
change_tick: Tick,
|
change_tick: Tick,
|
||||||
@ -40,9 +41,10 @@ impl<'w> BundleInserter<'w> {
|
|||||||
// SAFETY: These come from the same world. `world.components_registrator` can't be used since we borrow other fields too.
|
// SAFETY: These come from the same world. `world.components_registrator` can't be used since we borrow other fields too.
|
||||||
let mut registrator =
|
let mut registrator =
|
||||||
unsafe { ComponentsRegistrator::new(&mut world.components, &mut world.component_ids) };
|
unsafe { ComponentsRegistrator::new(&mut world.components, &mut world.component_ids) };
|
||||||
let bundle_id = world
|
let bundle_id =
|
||||||
.bundles
|
world
|
||||||
.register_info::<T>(&mut registrator, &mut world.storages);
|
.bundles
|
||||||
|
.register_info::<T>(bundle, &mut registrator, &mut world.storages);
|
||||||
// SAFETY: We just ensured this bundle exists
|
// SAFETY: We just ensured this bundle exists
|
||||||
unsafe { Self::new_with_id(world, archetype_id, bundle_id, change_tick) }
|
unsafe { Self::new_with_id(world, archetype_id, bundle_id, change_tick) }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -75,11 +75,13 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use bevy_ptr::OwningPtr;
|
use bevy_ptr::OwningPtr;
|
||||||
|
|
||||||
/// The `Bundle` trait enables insertion and removal of [`Component`]s from an entity.
|
/// 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'.
|
/// Implementers of the `Bundle` trait are called 'bundles'.
|
||||||
///
|
///
|
||||||
/// Each bundle represents a static set of [`Component`] types.
|
|
||||||
/// Currently, bundles can only contain one of each [`Component`], and will
|
/// Currently, bundles can only contain one of each [`Component`], and will
|
||||||
/// panic once initialized if this is not met.
|
/// panic once initialized if this is not met.
|
||||||
///
|
///
|
||||||
@ -109,15 +111,6 @@ use bevy_ptr::OwningPtr;
|
|||||||
/// contains the components of a bundle.
|
/// contains the components of a bundle.
|
||||||
/// Queries should instead only select the components they logically operate on.
|
/// Queries should instead only select the components they logically operate on.
|
||||||
///
|
///
|
||||||
/// ## Removal
|
|
||||||
///
|
|
||||||
/// Bundles are also 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.
|
|
||||||
///
|
|
||||||
/// # Implementers
|
/// # Implementers
|
||||||
///
|
///
|
||||||
/// Every type which implements [`Component`] also implements `Bundle`, since
|
/// Every type which implements [`Component`] also implements `Bundle`, since
|
||||||
@ -190,21 +183,65 @@ use bevy_ptr::OwningPtr;
|
|||||||
// bundle, in the _exact_ order that [`DynamicBundle::get_components`] is called.
|
// 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::from_components`] must call `func` exactly once for each [`ComponentId`] returned by
|
||||||
// [`Bundle::component_ids`].
|
// [`Bundle::component_ids`].
|
||||||
|
// - [`Bundle::component_ids`], [`Bundle::get_component_ids`] and [`Bundle::register_required_components`]
|
||||||
|
// cannot depend on `self` for now.
|
||||||
#[diagnostic::on_unimplemented(
|
#[diagnostic::on_unimplemented(
|
||||||
message = "`{Self}` is not a `Bundle`",
|
message = "`{Self}` is not a `Bundle`",
|
||||||
label = "invalid `Bundle`",
|
label = "invalid `Bundle`",
|
||||||
note = "consider annotating `{Self}` with `#[derive(Component)]` or `#[derive(Bundle)]`"
|
note = "consider annotating `{Self}` with `#[derive(Component)]` or `#[derive(Bundle)]`"
|
||||||
)]
|
)]
|
||||||
pub unsafe trait Bundle: DynamicBundle + Send + Sync + 'static {
|
pub unsafe trait Bundle: DynamicBundle + Send + Sync + 'static {
|
||||||
/// Gets this [`Bundle`]'s component ids, in the order of this bundle's [`Component`]s
|
/// 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)]
|
#[doc(hidden)]
|
||||||
fn component_ids(components: &mut ComponentsRegistrator, ids: &mut impl FnMut(ComponentId));
|
fn component_ids(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.
|
/// 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>));
|
fn get_component_ids(components: &Components, ids: &mut impl FnMut(Option<ComponentId>));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a [`Bundle`] by taking it from internal storage.
|
/// Creates a bundle by taking it from the internal storage.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
|
|||||||
@ -4,7 +4,7 @@ use core::ptr::NonNull;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
archetype::{Archetype, ArchetypeCreated, ArchetypeId, Archetypes},
|
archetype::{Archetype, ArchetypeCreated, ArchetypeId, Archetypes},
|
||||||
bundle::{Bundle, BundleId, BundleInfo},
|
bundle::{BundleId, BundleInfo, StaticBundle},
|
||||||
change_detection::MaybeLocation,
|
change_detection::MaybeLocation,
|
||||||
component::{ComponentId, Components, ComponentsRegistrator, StorageType},
|
component::{ComponentId, Components, ComponentsRegistrator, StorageType},
|
||||||
entity::{Entity, EntityLocation},
|
entity::{Entity, EntityLocation},
|
||||||
@ -33,7 +33,7 @@ impl<'w> BundleRemover<'w> {
|
|||||||
/// # Safety
|
/// # Safety
|
||||||
/// Caller must ensure that `archetype_id` is valid
|
/// Caller must ensure that `archetype_id` is valid
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) unsafe fn new<T: Bundle>(
|
pub(crate) unsafe fn new<T: StaticBundle>(
|
||||||
world: &'w mut World,
|
world: &'w mut World,
|
||||||
archetype_id: ArchetypeId,
|
archetype_id: ArchetypeId,
|
||||||
require_all: bool,
|
require_all: bool,
|
||||||
@ -43,7 +43,7 @@ impl<'w> BundleRemover<'w> {
|
|||||||
unsafe { ComponentsRegistrator::new(&mut world.components, &mut world.component_ids) };
|
unsafe { ComponentsRegistrator::new(&mut world.components, &mut world.component_ids) };
|
||||||
let bundle_id = world
|
let bundle_id = world
|
||||||
.bundles
|
.bundles
|
||||||
.register_info::<T>(&mut registrator, &mut world.storages);
|
.register_static_info::<T>(&mut registrator, &mut world.storages);
|
||||||
// SAFETY: we initialized this bundle_id in `init_info`, and caller ensures archetype is valid.
|
// SAFETY: we initialized this bundle_id in `init_info`, and caller ensures archetype is valid.
|
||||||
unsafe { Self::new_with_id(world, archetype_id, bundle_id, require_all) }
|
unsafe { Self::new_with_id(world, archetype_id, bundle_id, require_all) }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,7 @@ use bevy_ptr::ConstNonNull;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
archetype::{Archetype, ArchetypeCreated, ArchetypeId, SpawnBundleStatus},
|
archetype::{Archetype, ArchetypeCreated, ArchetypeId, SpawnBundleStatus},
|
||||||
bundle::{Bundle, BundleId, BundleInfo, DynamicBundle, InsertMode},
|
bundle::{Bundle, BundleId, BundleInfo, DynamicBundle, InsertMode, StaticBundle},
|
||||||
change_detection::MaybeLocation,
|
change_detection::MaybeLocation,
|
||||||
component::{ComponentsRegistrator, Tick},
|
component::{ComponentsRegistrator, Tick},
|
||||||
entity::{Entities, Entity, EntityLocation},
|
entity::{Entities, Entity, EntityLocation},
|
||||||
@ -25,13 +25,25 @@ pub(crate) struct BundleSpawner<'w> {
|
|||||||
|
|
||||||
impl<'w> BundleSpawner<'w> {
|
impl<'w> BundleSpawner<'w> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new<T: Bundle>(world: &'w mut World, change_tick: Tick) -> Self {
|
pub fn new<T: Bundle>(bundle: &T, world: &'w mut World, change_tick: Tick) -> Self {
|
||||||
// SAFETY: These come from the same world. `world.components_registrator` can't be used since we borrow other fields too.
|
// SAFETY: These come from the same world. `world.components_registrator` can't be used since we borrow other fields too.
|
||||||
let mut registrator =
|
let mut registrator =
|
||||||
unsafe { ComponentsRegistrator::new(&mut world.components, &mut world.component_ids) };
|
unsafe { ComponentsRegistrator::new(&mut world.components, &mut world.component_ids) };
|
||||||
let bundle_id = world
|
let bundle_id = world
|
||||||
.bundles
|
.bundles
|
||||||
.register_info::<T>(&mut registrator, &mut world.storages);
|
.register_info(bundle, &mut registrator, &mut world.storages);
|
||||||
|
// SAFETY: we initialized this bundle_id in `init_info`
|
||||||
|
unsafe { Self::new_with_id(world, bundle_id, change_tick) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn new_static<T: StaticBundle>(world: &'w mut World, change_tick: Tick) -> Self {
|
||||||
|
// SAFETY: These come from the same world. `world.components_registrator` can't be used since we borrow other fields too.
|
||||||
|
let mut registrator =
|
||||||
|
unsafe { ComponentsRegistrator::new(&mut world.components, &mut world.component_ids) };
|
||||||
|
let bundle_id = world
|
||||||
|
.bundles
|
||||||
|
.register_static_info::<T>(&mut registrator, &mut world.storages);
|
||||||
// SAFETY: we initialized this bundle_id in `init_info`
|
// SAFETY: we initialized this bundle_id in `init_info`
|
||||||
unsafe { Self::new_with_id(world, bundle_id, change_tick) }
|
unsafe { Self::new_with_id(world, bundle_id, change_tick) }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ use derive_more::derive::From;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
archetype::Archetype,
|
archetype::Archetype,
|
||||||
bundle::{Bundle, BundleId, BundleRemover, InsertMode},
|
bundle::{BundleId, BundleRemover, InsertMode, StaticBundle},
|
||||||
change_detection::MaybeLocation,
|
change_detection::MaybeLocation,
|
||||||
component::{Component, ComponentCloneBehavior, ComponentCloneFn, ComponentId, ComponentInfo},
|
component::{Component, ComponentCloneBehavior, ComponentCloneFn, ComponentId, ComponentInfo},
|
||||||
entity::{hash_map::EntityHashMap, Entities, Entity, EntityMapper},
|
entity::{hash_map::EntityHashMap, Entities, Entity, EntityMapper},
|
||||||
@ -911,7 +911,7 @@ impl<'w> EntityClonerBuilder<'w, OptOut> {
|
|||||||
/// If component `A` is denied here and component `B` requires `A`, then `A`
|
/// If component `A` is denied here and component `B` requires `A`, then `A`
|
||||||
/// is denied as well. See [`Self::without_required_by_components`] to alter
|
/// is denied as well. See [`Self::without_required_by_components`] to alter
|
||||||
/// this behavior.
|
/// this behavior.
|
||||||
pub fn deny<T: Bundle>(&mut self) -> &mut Self {
|
pub fn deny<T: StaticBundle>(&mut self) -> &mut Self {
|
||||||
let bundle_id = self.world.register_bundle::<T>().id();
|
let bundle_id = self.world.register_bundle::<T>().id();
|
||||||
self.deny_by_ids(bundle_id)
|
self.deny_by_ids(bundle_id)
|
||||||
}
|
}
|
||||||
@ -968,7 +968,7 @@ impl<'w> EntityClonerBuilder<'w, OptIn> {
|
|||||||
/// If component `A` is allowed here and requires component `B`, then `B`
|
/// If component `A` is allowed here and requires component `B`, then `B`
|
||||||
/// is allowed as well. See [`Self::without_required_components`]
|
/// is allowed as well. See [`Self::without_required_components`]
|
||||||
/// to alter this behavior.
|
/// to alter this behavior.
|
||||||
pub fn allow<T: Bundle>(&mut self) -> &mut Self {
|
pub fn allow<T: StaticBundle>(&mut self) -> &mut Self {
|
||||||
let bundle_id = self.world.register_bundle::<T>().id();
|
let bundle_id = self.world.register_bundle::<T>().id();
|
||||||
self.allow_by_ids(bundle_id)
|
self.allow_by_ids(bundle_id)
|
||||||
}
|
}
|
||||||
@ -979,7 +979,7 @@ impl<'w> EntityClonerBuilder<'w, OptIn> {
|
|||||||
/// If component `A` is allowed here and requires component `B`, then `B`
|
/// If component `A` is allowed here and requires component `B`, then `B`
|
||||||
/// is allowed as well. See [`Self::without_required_components`]
|
/// is allowed as well. See [`Self::without_required_components`]
|
||||||
/// to alter this behavior.
|
/// to alter this behavior.
|
||||||
pub fn allow_if_new<T: Bundle>(&mut self) -> &mut Self {
|
pub fn allow_if_new<T: StaticBundle>(&mut self) -> &mut Self {
|
||||||
let bundle_id = self.world.register_bundle::<T>().id();
|
let bundle_id = self.world.register_bundle::<T>().id();
|
||||||
self.allow_by_ids_if_new(bundle_id)
|
self.allow_by_ids_if_new(bundle_id)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -146,7 +146,7 @@ pub struct HotPatched;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
bundle::Bundle,
|
bundle::{Bundle, StaticBundle},
|
||||||
change_detection::Ref,
|
change_detection::Ref,
|
||||||
component::{Component, ComponentId, RequiredComponents, RequiredComponentsError},
|
component::{Component, ComponentId, RequiredComponents, RequiredComponentsError},
|
||||||
entity::{Entity, EntityMapper},
|
entity::{Entity, EntityMapper},
|
||||||
@ -242,11 +242,18 @@ mod tests {
|
|||||||
x: TableStored,
|
x: TableStored,
|
||||||
y: SparseStored,
|
y: SparseStored,
|
||||||
}
|
}
|
||||||
let mut ids = Vec::new();
|
|
||||||
<FooBundle as Bundle>::component_ids(&mut world.components_registrator(), &mut |id| {
|
|
||||||
ids.push(id);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
let mut ids = Vec::new();
|
||||||
|
<FooBundle as Bundle>::component_ids(
|
||||||
|
&FooBundle {
|
||||||
|
x: TableStored("abc"),
|
||||||
|
y: SparseStored(123),
|
||||||
|
},
|
||||||
|
&mut world.components_registrator(),
|
||||||
|
&mut |id| {
|
||||||
|
ids.push(id);
|
||||||
|
},
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ids,
|
ids,
|
||||||
&[
|
&[
|
||||||
@ -255,6 +262,21 @@ mod tests {
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let mut static_ids = Vec::new();
|
||||||
|
<FooBundle as StaticBundle>::component_ids(
|
||||||
|
&mut world.components_registrator(),
|
||||||
|
&mut |id| {
|
||||||
|
static_ids.push(id);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
static_ids,
|
||||||
|
&[
|
||||||
|
world.register_component::<TableStored>(),
|
||||||
|
world.register_component::<SparseStored>(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
let e1 = world
|
let e1 = world
|
||||||
.spawn(FooBundle {
|
.spawn(FooBundle {
|
||||||
x: TableStored("abc"),
|
x: TableStored("abc"),
|
||||||
@ -293,10 +315,20 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut ids = Vec::new();
|
let mut ids = Vec::new();
|
||||||
<NestedBundle as Bundle>::component_ids(&mut world.components_registrator(), &mut |id| {
|
<NestedBundle as Bundle>::component_ids(
|
||||||
ids.push(id);
|
&NestedBundle {
|
||||||
});
|
a: A(1),
|
||||||
|
foo: FooBundle {
|
||||||
|
x: TableStored("ghi"),
|
||||||
|
y: SparseStored(789),
|
||||||
|
},
|
||||||
|
b: B(2),
|
||||||
|
},
|
||||||
|
&mut world.components_registrator(),
|
||||||
|
&mut |id| {
|
||||||
|
ids.push(id);
|
||||||
|
},
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ids,
|
ids,
|
||||||
&[
|
&[
|
||||||
@ -307,6 +339,23 @@ mod tests {
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let mut static_ids = Vec::new();
|
||||||
|
<NestedBundle as StaticBundle>::component_ids(
|
||||||
|
&mut world.components_registrator(),
|
||||||
|
&mut |id| {
|
||||||
|
static_ids.push(id);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
static_ids,
|
||||||
|
&[
|
||||||
|
world.register_component::<A>(),
|
||||||
|
world.register_component::<TableStored>(),
|
||||||
|
world.register_component::<SparseStored>(),
|
||||||
|
world.register_component::<B>(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
let e3 = world
|
let e3 = world
|
||||||
.spawn(NestedBundle {
|
.spawn(NestedBundle {
|
||||||
a: A(1),
|
a: A(1),
|
||||||
@ -346,13 +395,25 @@ mod tests {
|
|||||||
|
|
||||||
let mut ids = Vec::new();
|
let mut ids = Vec::new();
|
||||||
<BundleWithIgnored as Bundle>::component_ids(
|
<BundleWithIgnored as Bundle>::component_ids(
|
||||||
|
&BundleWithIgnored {
|
||||||
|
c: C,
|
||||||
|
ignored: Ignored,
|
||||||
|
},
|
||||||
&mut world.components_registrator(),
|
&mut world.components_registrator(),
|
||||||
&mut |id| {
|
&mut |id| {
|
||||||
ids.push(id);
|
ids.push(id);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
assert_eq!(ids, &[world.register_component::<C>()]);
|
||||||
|
|
||||||
assert_eq!(ids, &[world.register_component::<C>(),]);
|
let mut static_ids = Vec::new();
|
||||||
|
<BundleWithIgnored as StaticBundle>::component_ids(
|
||||||
|
&mut world.components_registrator(),
|
||||||
|
&mut |id| {
|
||||||
|
static_ids.push(id);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
assert_eq!(static_ids, &[world.register_component::<C>()]);
|
||||||
|
|
||||||
let e4 = world
|
let e4 = world
|
||||||
.spawn(BundleWithIgnored {
|
.spawn(BundleWithIgnored {
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
use core::any::Any;
|
use core::any::Any;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
bundle::StaticBundle,
|
||||||
component::{ComponentCloneBehavior, ComponentId, Mutable, StorageType},
|
component::{ComponentCloneBehavior, ComponentId, Mutable, StorageType},
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
error::{ErrorContext, ErrorHandler},
|
error::{ErrorContext, ErrorHandler},
|
||||||
@ -217,7 +218,7 @@ impl Observer {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if the given system is an exclusive system.
|
/// Panics if the given system is an exclusive system.
|
||||||
pub fn new<E: Event, B: Bundle, M, I: IntoObserverSystem<E, B, M>>(system: I) -> Self {
|
pub fn new<E: Event, B: StaticBundle, M, I: IntoObserverSystem<E, B, M>>(system: I) -> Self {
|
||||||
let system = Box::new(IntoObserverSystem::into_system(system));
|
let system = Box::new(IntoObserverSystem::into_system(system));
|
||||||
assert!(
|
assert!(
|
||||||
!system.is_exclusive(),
|
!system.is_exclusive(),
|
||||||
@ -405,7 +406,7 @@ impl ObserverDescriptor {
|
|||||||
/// The type parameters of this function _must_ match those used to create the [`Observer`].
|
/// The type parameters of this function _must_ match those used to create the [`Observer`].
|
||||||
/// As such, it is recommended to only use this function within the [`Observer::new`] method to
|
/// As such, it is recommended to only use this function within the [`Observer::new`] method to
|
||||||
/// ensure type parameters match.
|
/// ensure type parameters match.
|
||||||
fn hook_on_add<E: Event, B: Bundle, S: ObserverSystem<E, B>>(
|
fn hook_on_add<E: Event, B: StaticBundle, S: ObserverSystem<E, B>>(
|
||||||
mut world: DeferredWorld<'_>,
|
mut world: DeferredWorld<'_>,
|
||||||
HookContext { entity, .. }: HookContext,
|
HookContext { entity, .. }: HookContext,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -143,6 +143,7 @@ pub use system_param::*;
|
|||||||
pub use trigger_targets::*;
|
pub use trigger_targets::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
bundle::StaticBundle,
|
||||||
change_detection::MaybeLocation,
|
change_detection::MaybeLocation,
|
||||||
component::ComponentId,
|
component::ComponentId,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
@ -179,7 +180,7 @@ impl World {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if the given system is an exclusive system.
|
/// Panics if the given system is an exclusive system.
|
||||||
pub fn add_observer<E: Event, B: Bundle, M>(
|
pub fn add_observer<E: Event, B: StaticBundle, M>(
|
||||||
&mut self,
|
&mut self,
|
||||||
system: impl IntoObserverSystem<E, B, M>,
|
system: impl IntoObserverSystem<E, B, M>,
|
||||||
) -> EntityWorldMut {
|
) -> EntityWorldMut {
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
use core::any::Any;
|
use core::any::Any;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
bundle::StaticBundle,
|
||||||
error::ErrorContext,
|
error::ErrorContext,
|
||||||
observer::ObserverTrigger,
|
observer::ObserverTrigger,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
@ -18,7 +19,7 @@ use bevy_ptr::PtrMut;
|
|||||||
/// but can be overridden for custom behavior.
|
/// but can be overridden for custom behavior.
|
||||||
pub type ObserverRunner = fn(DeferredWorld, ObserverTrigger, PtrMut, propagate: &mut bool);
|
pub type ObserverRunner = fn(DeferredWorld, ObserverTrigger, PtrMut, propagate: &mut bool);
|
||||||
|
|
||||||
pub(super) fn observer_system_runner<E: Event, B: Bundle, S: ObserverSystem<E, B>>(
|
pub(super) fn observer_system_runner<E: Event, B: StaticBundle, S: ObserverSystem<E, B>>(
|
||||||
mut world: DeferredWorld,
|
mut world: DeferredWorld,
|
||||||
observer_trigger: ObserverTrigger,
|
observer_trigger: ObserverTrigger,
|
||||||
ptr: PtrMut,
|
ptr: PtrMut,
|
||||||
|
|||||||
@ -8,8 +8,8 @@ use bevy_ptr::Ptr;
|
|||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bundle::Bundle, change_detection::MaybeLocation, component::ComponentId, event::EntityEvent,
|
bundle::StaticBundle, change_detection::MaybeLocation, component::ComponentId,
|
||||||
prelude::*,
|
event::EntityEvent, prelude::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Type containing triggered [`Event`] information for a given run of an [`Observer`]. This contains the
|
/// Type containing triggered [`Event`] information for a given run of an [`Observer`]. This contains the
|
||||||
@ -26,7 +26,7 @@ use crate::{
|
|||||||
/// Providing multiple components in this bundle will cause this event to be triggered by any
|
/// Providing multiple components in this bundle will cause this event to be triggered by any
|
||||||
/// matching component in the bundle,
|
/// matching component in the bundle,
|
||||||
/// [rather than requiring all of them to be present](https://github.com/bevyengine/bevy/issues/15325).
|
/// [rather than requiring all of them to be present](https://github.com/bevyengine/bevy/issues/15325).
|
||||||
pub struct On<'w, E, B: Bundle = ()> {
|
pub struct On<'w, E, B: StaticBundle = ()> {
|
||||||
event: &'w mut E,
|
event: &'w mut E,
|
||||||
propagate: &'w mut bool,
|
propagate: &'w mut bool,
|
||||||
trigger: ObserverTrigger,
|
trigger: ObserverTrigger,
|
||||||
@ -37,7 +37,7 @@ pub struct On<'w, E, B: Bundle = ()> {
|
|||||||
#[deprecated(since = "0.17.0", note = "Renamed to `On`.")]
|
#[deprecated(since = "0.17.0", note = "Renamed to `On`.")]
|
||||||
pub type Trigger<'w, E, B = ()> = On<'w, E, B>;
|
pub type Trigger<'w, E, B = ()> = On<'w, E, B>;
|
||||||
|
|
||||||
impl<'w, E, B: Bundle> On<'w, E, B> {
|
impl<'w, E, B: StaticBundle> On<'w, E, B> {
|
||||||
/// Creates a new instance of [`On`] for the given event and observer information.
|
/// Creates a new instance of [`On`] for the given event and observer information.
|
||||||
pub fn new(event: &'w mut E, propagate: &'w mut bool, trigger: ObserverTrigger) -> Self {
|
pub fn new(event: &'w mut E, propagate: &'w mut bool, trigger: ObserverTrigger) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -105,7 +105,7 @@ impl<'w, E, B: Bundle> On<'w, E, B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, E: EntityEvent, B: Bundle> On<'w, E, B> {
|
impl<'w, E: EntityEvent, B: StaticBundle> On<'w, E, B> {
|
||||||
/// Returns the [`Entity`] that was targeted by the `event` that triggered this observer.
|
/// Returns the [`Entity`] that was targeted by the `event` that triggered this observer.
|
||||||
///
|
///
|
||||||
/// Note that if event propagation is enabled, this may not be the same as the original target of the event,
|
/// Note that if event propagation is enabled, this may not be the same as the original target of the event,
|
||||||
@ -149,7 +149,7 @@ impl<'w, E: EntityEvent, B: Bundle> On<'w, E, B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, E: Debug, B: Bundle> Debug for On<'w, E, B> {
|
impl<'w, E: Debug, B: StaticBundle> Debug for On<'w, E, B> {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
f.debug_struct("On")
|
f.debug_struct("On")
|
||||||
.field("event", &self.event)
|
.field("event", &self.event)
|
||||||
@ -160,7 +160,7 @@ impl<'w, E: Debug, B: Bundle> Debug for On<'w, E, B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, E, B: Bundle> Deref for On<'w, E, B> {
|
impl<'w, E, B: StaticBundle> Deref for On<'w, E, B> {
|
||||||
type Target = E;
|
type Target = E;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
@ -168,7 +168,7 @@ impl<'w, E, B: Bundle> Deref for On<'w, E, B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, E, B: Bundle> DerefMut for On<'w, E, B> {
|
impl<'w, E, B: StaticBundle> DerefMut for On<'w, E, B> {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
self.event
|
self.event
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
archetype::{Archetype, Archetypes},
|
archetype::{Archetype, Archetypes},
|
||||||
bundle::Bundle,
|
bundle::StaticBundle,
|
||||||
change_detection::{MaybeLocation, Ticks, TicksMut},
|
change_detection::{MaybeLocation, Ticks, TicksMut},
|
||||||
component::{Component, ComponentId, Components, Mutable, StorageType, Tick},
|
component::{Component, ComponentId, Components, Mutable, StorageType, Tick},
|
||||||
entity::{Entities, Entity, EntityLocation},
|
entity::{Entities, Entity, EntityLocation},
|
||||||
@ -1168,7 +1168,7 @@ unsafe impl<'a> QueryData for FilteredEntityMut<'a> {
|
|||||||
/// are rejected.
|
/// are rejected.
|
||||||
unsafe impl<'a, B> WorldQuery for EntityRefExcept<'a, B>
|
unsafe impl<'a, B> WorldQuery for EntityRefExcept<'a, B>
|
||||||
where
|
where
|
||||||
B: Bundle,
|
B: StaticBundle,
|
||||||
{
|
{
|
||||||
type Fetch<'w> = EntityFetch<'w>;
|
type Fetch<'w> = EntityFetch<'w>;
|
||||||
type State = SmallVec<[ComponentId; 4]>;
|
type State = SmallVec<[ComponentId; 4]>;
|
||||||
@ -1243,7 +1243,7 @@ where
|
|||||||
/// SAFETY: `Self` is the same as `Self::ReadOnly`.
|
/// SAFETY: `Self` is the same as `Self::ReadOnly`.
|
||||||
unsafe impl<'a, B> QueryData for EntityRefExcept<'a, B>
|
unsafe impl<'a, B> QueryData for EntityRefExcept<'a, B>
|
||||||
where
|
where
|
||||||
B: Bundle,
|
B: StaticBundle,
|
||||||
{
|
{
|
||||||
const IS_READ_ONLY: bool = true;
|
const IS_READ_ONLY: bool = true;
|
||||||
type ReadOnly = Self;
|
type ReadOnly = Self;
|
||||||
@ -1271,14 +1271,14 @@ where
|
|||||||
|
|
||||||
/// SAFETY: `EntityRefExcept` enforces read-only access to its contained
|
/// SAFETY: `EntityRefExcept` enforces read-only access to its contained
|
||||||
/// components.
|
/// components.
|
||||||
unsafe impl<'a, B> ReadOnlyQueryData for EntityRefExcept<'a, B> where B: Bundle {}
|
unsafe impl<'a, B> ReadOnlyQueryData for EntityRefExcept<'a, B> where B: StaticBundle {}
|
||||||
|
|
||||||
/// SAFETY: `EntityMutExcept` guards access to all components in the bundle `B`
|
/// SAFETY: `EntityMutExcept` guards access to all components in the bundle `B`
|
||||||
/// and populates `Access` values so that queries that conflict with this access
|
/// and populates `Access` values so that queries that conflict with this access
|
||||||
/// are rejected.
|
/// are rejected.
|
||||||
unsafe impl<'a, B> WorldQuery for EntityMutExcept<'a, B>
|
unsafe impl<'a, B> WorldQuery for EntityMutExcept<'a, B>
|
||||||
where
|
where
|
||||||
B: Bundle,
|
B: StaticBundle,
|
||||||
{
|
{
|
||||||
type Fetch<'w> = EntityFetch<'w>;
|
type Fetch<'w> = EntityFetch<'w>;
|
||||||
type State = SmallVec<[ComponentId; 4]>;
|
type State = SmallVec<[ComponentId; 4]>;
|
||||||
@ -1354,7 +1354,7 @@ where
|
|||||||
/// `EntityMutExcept` provides.
|
/// `EntityMutExcept` provides.
|
||||||
unsafe impl<'a, B> QueryData for EntityMutExcept<'a, B>
|
unsafe impl<'a, B> QueryData for EntityMutExcept<'a, B>
|
||||||
where
|
where
|
||||||
B: Bundle,
|
B: StaticBundle,
|
||||||
{
|
{
|
||||||
const IS_READ_ONLY: bool = false;
|
const IS_READ_ONLY: bool = false;
|
||||||
type ReadOnly = EntityRefExcept<'a, B>;
|
type ReadOnly = EntityRefExcept<'a, B>;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use super::{QueryData, QueryFilter, ReadOnlyQueryData};
|
use super::{QueryData, QueryFilter, ReadOnlyQueryData};
|
||||||
use crate::{
|
use crate::{
|
||||||
archetype::{Archetype, ArchetypeEntity, Archetypes},
|
archetype::{Archetype, ArchetypeEntity, Archetypes},
|
||||||
bundle::Bundle,
|
bundle::StaticBundle,
|
||||||
component::Tick,
|
component::Tick,
|
||||||
entity::{ContainsEntity, Entities, Entity, EntityEquivalent, EntitySet, EntitySetIterator},
|
entity::{ContainsEntity, Entities, Entity, EntityEquivalent, EntitySet, EntitySetIterator},
|
||||||
query::{ArchetypeFilter, DebugCheckedUnwrap, QueryState, StorageId},
|
query::{ArchetypeFilter, DebugCheckedUnwrap, QueryState, StorageId},
|
||||||
@ -969,13 +969,13 @@ unsafe impl<'w, 's, F: QueryFilter> EntitySetIterator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: [`QueryIter`] is guaranteed to return every matching entity once and only once.
|
// SAFETY: [`QueryIter`] is guaranteed to return every matching entity once and only once.
|
||||||
unsafe impl<'w, 's, F: QueryFilter, B: Bundle> EntitySetIterator
|
unsafe impl<'w, 's, F: QueryFilter, B: StaticBundle> EntitySetIterator
|
||||||
for QueryIter<'w, 's, EntityRefExcept<'_, B>, F>
|
for QueryIter<'w, 's, EntityRefExcept<'_, B>, F>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: [`QueryIter`] is guaranteed to return every matching entity once and only once.
|
// SAFETY: [`QueryIter`] is guaranteed to return every matching entity once and only once.
|
||||||
unsafe impl<'w, 's, F: QueryFilter, B: Bundle> EntitySetIterator
|
unsafe impl<'w, 's, F: QueryFilter, B: StaticBundle> EntitySetIterator
|
||||||
for QueryIter<'w, 's, EntityMutExcept<'_, B>, F>
|
for QueryIter<'w, 's, EntityMutExcept<'_, B>, F>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ use bevy_utils::prelude::DebugName;
|
|||||||
use core::any::{Any, TypeId};
|
use core::any::{Any, TypeId};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bundle::BundleFromComponents,
|
bundle::{BundleFromComponents, StaticBundle},
|
||||||
entity::EntityMapper,
|
entity::EntityMapper,
|
||||||
prelude::Bundle,
|
prelude::Bundle,
|
||||||
relationship::RelationshipHookMode,
|
relationship::RelationshipHookMode,
|
||||||
@ -57,7 +57,7 @@ impl ReflectBundleFns {
|
|||||||
///
|
///
|
||||||
/// This is useful if you want to start with the default implementation before overriding some
|
/// This is useful if you want to start with the default implementation before overriding some
|
||||||
/// of the functions to create a custom implementation.
|
/// of the functions to create a custom implementation.
|
||||||
pub fn new<T: Bundle + FromReflect + TypePath + BundleFromComponents>() -> Self {
|
pub fn new<T: Bundle + StaticBundle + FromReflect + TypePath + BundleFromComponents>() -> Self {
|
||||||
<ReflectBundle as FromType<T>>::from_type().0
|
<ReflectBundle as FromType<T>>::from_type().0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,7 +148,9 @@ impl ReflectBundle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: Bundle + Reflect + TypePath + BundleFromComponents> FromType<B> for ReflectBundle {
|
impl<B: Bundle + StaticBundle + Reflect + TypePath + BundleFromComponents> FromType<B>
|
||||||
|
for ReflectBundle
|
||||||
|
{
|
||||||
fn from_type() -> Self {
|
fn from_type() -> Self {
|
||||||
ReflectBundle(ReflectBundleFns {
|
ReflectBundle(ReflectBundleFns {
|
||||||
insert: |entity, reflected_bundle, registry| {
|
insert: |entity, reflected_bundle, registry| {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
bundle::Bundle,
|
bundle::{Bundle, StaticBundle},
|
||||||
entity::{hash_set::EntityHashSet, Entity},
|
entity::{hash_set::EntityHashSet, Entity},
|
||||||
prelude::Children,
|
prelude::Children,
|
||||||
relationship::{
|
relationship::{
|
||||||
@ -355,7 +355,7 @@ impl<'w> EntityWorldMut<'w> {
|
|||||||
///
|
///
|
||||||
/// This method should only be called on relationships that form a tree-like structure.
|
/// This method should only be called on relationships that form a tree-like structure.
|
||||||
/// Any cycles will cause this method to loop infinitely.
|
/// Any cycles will cause this method to loop infinitely.
|
||||||
pub fn remove_recursive<S: RelationshipTarget, B: Bundle>(&mut self) -> &mut Self {
|
pub fn remove_recursive<S: RelationshipTarget, B: StaticBundle>(&mut self) -> &mut Self {
|
||||||
self.remove::<B>();
|
self.remove::<B>();
|
||||||
if let Some(relationship_target) = self.get::<S>() {
|
if let Some(relationship_target) = self.get::<S>() {
|
||||||
let related_vec: Vec<Entity> = relationship_target.iter().collect();
|
let related_vec: Vec<Entity> = relationship_target.iter().collect();
|
||||||
@ -550,7 +550,7 @@ impl<'a> EntityCommands<'a> {
|
|||||||
///
|
///
|
||||||
/// This method should only be called on relationships that form a tree-like structure.
|
/// This method should only be called on relationships that form a tree-like structure.
|
||||||
/// Any cycles will cause this method to loop infinitely.
|
/// Any cycles will cause this method to loop infinitely.
|
||||||
pub fn remove_recursive<S: RelationshipTarget, B: Bundle>(&mut self) -> &mut Self {
|
pub fn remove_recursive<S: RelationshipTarget, B: StaticBundle>(&mut self) -> &mut Self {
|
||||||
self.queue(move |mut entity: EntityWorldMut| {
|
self.queue(move |mut entity: EntityWorldMut| {
|
||||||
entity.remove_recursive::<S, B>();
|
entity.remove_recursive::<S, B>();
|
||||||
})
|
})
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
//! for the best entry points into these APIs and examples of how to use them.
|
//! for the best entry points into these APIs and examples of how to use them.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bundle::{Bundle, BundleEffect, DynamicBundle, NoBundleEffect},
|
bundle::{Bundle, BundleEffect, DynamicBundle, NoBundleEffect, StaticBundle},
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
relationship::{RelatedSpawner, Relationship, RelationshipTarget},
|
relationship::{RelatedSpawner, Relationship, RelationshipTarget},
|
||||||
world::{EntityWorldMut, World},
|
world::{EntityWorldMut, World},
|
||||||
@ -46,7 +46,9 @@ pub trait SpawnableList<R> {
|
|||||||
fn size_hint(&self) -> usize;
|
fn size_hint(&self) -> usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Relationship, B: Bundle<Effect: NoBundleEffect>> SpawnableList<R> for Vec<B> {
|
impl<R: Relationship, B: Bundle<Effect: NoBundleEffect> + StaticBundle> SpawnableList<R>
|
||||||
|
for Vec<B>
|
||||||
|
{
|
||||||
fn spawn(self, world: &mut World, entity: Entity) {
|
fn spawn(self, world: &mut World, entity: Entity) {
|
||||||
let mapped_bundles = self.into_iter().map(|b| (R::from(entity), b));
|
let mapped_bundles = self.into_iter().map(|b| (R::from(entity), b));
|
||||||
world.spawn_batch(mapped_bundles);
|
world.spawn_batch(mapped_bundles);
|
||||||
@ -182,22 +184,43 @@ impl<R: Relationship, L: SpawnableList<R>> BundleEffect for SpawnRelatedBundle<R
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: This internally relies on the RelationshipTarget's Bundle implementation, which is sound.
|
// SAFETY: This internally relies on the RelationshipTarget's StaticBundle implementation, which is sound.
|
||||||
unsafe impl<R: Relationship, L: SpawnableList<R> + Send + Sync + 'static> Bundle
|
unsafe impl<R: Relationship, L: SpawnableList<R> + Send + Sync + 'static> StaticBundle
|
||||||
for SpawnRelatedBundle<R, L>
|
for SpawnRelatedBundle<R, L>
|
||||||
{
|
{
|
||||||
fn component_ids(
|
fn component_ids(
|
||||||
components: &mut crate::component::ComponentsRegistrator,
|
components: &mut crate::component::ComponentsRegistrator,
|
||||||
ids: &mut impl FnMut(crate::component::ComponentId),
|
ids: &mut impl FnMut(crate::component::ComponentId),
|
||||||
) {
|
) {
|
||||||
<R::RelationshipTarget as Bundle>::component_ids(components, ids);
|
<R::RelationshipTarget as StaticBundle>::component_ids(components, ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_component_ids(
|
fn get_component_ids(
|
||||||
components: &crate::component::Components,
|
components: &crate::component::Components,
|
||||||
ids: &mut impl FnMut(Option<crate::component::ComponentId>),
|
ids: &mut impl FnMut(Option<crate::component::ComponentId>),
|
||||||
) {
|
) {
|
||||||
<R::RelationshipTarget as Bundle>::get_component_ids(components, ids);
|
<R::RelationshipTarget as StaticBundle>::get_component_ids(components, ids);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SAFETY: This internally relies on the RelationshipTarget's Bundle implementation, which is sound.
|
||||||
|
unsafe impl<R: Relationship, L: SpawnableList<R> + Send + Sync + 'static> Bundle
|
||||||
|
for SpawnRelatedBundle<R, L>
|
||||||
|
{
|
||||||
|
fn component_ids(
|
||||||
|
&self,
|
||||||
|
components: &mut crate::component::ComponentsRegistrator,
|
||||||
|
ids: &mut impl FnMut(crate::component::ComponentId),
|
||||||
|
) {
|
||||||
|
<Self as StaticBundle>::component_ids(components, ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_component_ids(
|
||||||
|
&self,
|
||||||
|
components: &crate::component::Components,
|
||||||
|
ids: &mut impl FnMut(Option<crate::component::ComponentId>),
|
||||||
|
) {
|
||||||
|
<Self as StaticBundle>::get_component_ids(components, ids);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,21 +264,39 @@ impl<R: Relationship, B: Bundle> DynamicBundle for SpawnOneRelated<R, B> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// SAFETY: This internally relies on the RelationshipTarget's StaticBundle implementation, which is sound.
|
||||||
// SAFETY: This internally relies on the RelationshipTarget's Bundle implementation, which is sound.
|
unsafe impl<R: Relationship, B: Bundle> StaticBundle for SpawnOneRelated<R, B> {
|
||||||
unsafe impl<R: Relationship, B: Bundle> Bundle for SpawnOneRelated<R, B> {
|
|
||||||
fn component_ids(
|
fn component_ids(
|
||||||
components: &mut crate::component::ComponentsRegistrator,
|
components: &mut crate::component::ComponentsRegistrator,
|
||||||
ids: &mut impl FnMut(crate::component::ComponentId),
|
ids: &mut impl FnMut(crate::component::ComponentId),
|
||||||
) {
|
) {
|
||||||
<R::RelationshipTarget as Bundle>::component_ids(components, ids);
|
<R::RelationshipTarget as StaticBundle>::component_ids(components, ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_component_ids(
|
fn get_component_ids(
|
||||||
components: &crate::component::Components,
|
components: &crate::component::Components,
|
||||||
ids: &mut impl FnMut(Option<crate::component::ComponentId>),
|
ids: &mut impl FnMut(Option<crate::component::ComponentId>),
|
||||||
) {
|
) {
|
||||||
<R::RelationshipTarget as Bundle>::get_component_ids(components, ids);
|
<R::RelationshipTarget as StaticBundle>::get_component_ids(components, ids);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SAFETY: This internally relies on the RelationshipTarget's Bundle implementation, which is sound.
|
||||||
|
unsafe impl<R: Relationship, B: Bundle> Bundle for SpawnOneRelated<R, B> {
|
||||||
|
fn component_ids(
|
||||||
|
&self,
|
||||||
|
components: &mut crate::component::ComponentsRegistrator,
|
||||||
|
ids: &mut impl FnMut(crate::component::ComponentId),
|
||||||
|
) {
|
||||||
|
<Self as StaticBundle>::component_ids(components, ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_component_ids(
|
||||||
|
&self,
|
||||||
|
components: &crate::component::Components,
|
||||||
|
ids: &mut impl FnMut(Option<crate::component::ComponentId>),
|
||||||
|
) {
|
||||||
|
<Self as StaticBundle>::get_component_ids(components, ids);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
//! [`Commands`](crate::system::Commands).
|
//! [`Commands`](crate::system::Commands).
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bundle::{Bundle, InsertMode, NoBundleEffect},
|
bundle::{Bundle, InsertMode, NoBundleEffect, StaticBundle},
|
||||||
change_detection::MaybeLocation,
|
change_detection::MaybeLocation,
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
error::Result,
|
error::Result,
|
||||||
@ -70,7 +70,7 @@ where
|
|||||||
pub fn spawn_batch<I>(bundles_iter: I) -> impl Command
|
pub fn spawn_batch<I>(bundles_iter: I) -> impl Command
|
||||||
where
|
where
|
||||||
I: IntoIterator + Send + Sync + 'static,
|
I: IntoIterator + Send + Sync + 'static,
|
||||||
I::Item: Bundle<Effect: NoBundleEffect>,
|
I::Item: Bundle<Effect: NoBundleEffect> + StaticBundle,
|
||||||
{
|
{
|
||||||
let caller = MaybeLocation::caller();
|
let caller = MaybeLocation::caller();
|
||||||
move |world: &mut World| {
|
move |world: &mut World| {
|
||||||
@ -88,7 +88,7 @@ where
|
|||||||
pub fn insert_batch<I, B>(batch: I, insert_mode: InsertMode) -> impl Command<Result>
|
pub fn insert_batch<I, B>(batch: I, insert_mode: InsertMode) -> impl Command<Result>
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
|
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
|
||||||
B: Bundle<Effect: NoBundleEffect>,
|
B: Bundle<Effect: NoBundleEffect> + StaticBundle,
|
||||||
{
|
{
|
||||||
let caller = MaybeLocation::caller();
|
let caller = MaybeLocation::caller();
|
||||||
move |world: &mut World| -> Result {
|
move |world: &mut World| -> Result {
|
||||||
|
|||||||
@ -8,7 +8,7 @@ use alloc::vec::Vec;
|
|||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bundle::{Bundle, InsertMode},
|
bundle::{Bundle, InsertMode, StaticBundle},
|
||||||
change_detection::MaybeLocation,
|
change_detection::MaybeLocation,
|
||||||
component::{Component, ComponentId, ComponentInfo},
|
component::{Component, ComponentId, ComponentInfo},
|
||||||
entity::{Entity, EntityClonerBuilder, OptIn, OptOut},
|
entity::{Entity, EntityClonerBuilder, OptIn, OptOut},
|
||||||
@ -180,7 +180,7 @@ where
|
|||||||
|
|
||||||
/// An [`EntityCommand`] that removes the components in a [`Bundle`] from an entity.
|
/// An [`EntityCommand`] that removes the components in a [`Bundle`] from an entity.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn remove<T: Bundle>() -> impl EntityCommand {
|
pub fn remove<T: StaticBundle>() -> impl EntityCommand {
|
||||||
let caller = MaybeLocation::caller();
|
let caller = MaybeLocation::caller();
|
||||||
move |mut entity: EntityWorldMut| {
|
move |mut entity: EntityWorldMut| {
|
||||||
entity.remove_with_caller::<T>(caller);
|
entity.remove_with_caller::<T>(caller);
|
||||||
@ -190,7 +190,7 @@ pub fn remove<T: Bundle>() -> impl EntityCommand {
|
|||||||
/// An [`EntityCommand`] that removes the components in a [`Bundle`] from an entity,
|
/// An [`EntityCommand`] that removes the components in a [`Bundle`] from an entity,
|
||||||
/// as well as the required components for each component removed.
|
/// as well as the required components for each component removed.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn remove_with_requires<T: Bundle>() -> impl EntityCommand {
|
pub fn remove_with_requires<T: StaticBundle>() -> impl EntityCommand {
|
||||||
let caller = MaybeLocation::caller();
|
let caller = MaybeLocation::caller();
|
||||||
move |mut entity: EntityWorldMut| {
|
move |mut entity: EntityWorldMut| {
|
||||||
entity.remove_with_requires_with_caller::<T>(caller);
|
entity.remove_with_requires_with_caller::<T>(caller);
|
||||||
@ -216,9 +216,9 @@ pub fn clear() -> impl EntityCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An [`EntityCommand`] that removes all components from an entity,
|
/// An [`EntityCommand`] that removes all components from an entity,
|
||||||
/// except for those in the given [`Bundle`].
|
/// except for those in the given [`StaticBundle`].
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn retain<T: Bundle>() -> impl EntityCommand {
|
pub fn retain<T: StaticBundle>() -> impl EntityCommand {
|
||||||
let caller = MaybeLocation::caller();
|
let caller = MaybeLocation::caller();
|
||||||
move |mut entity: EntityWorldMut| {
|
move |mut entity: EntityWorldMut| {
|
||||||
entity.retain_with_caller::<T>(caller);
|
entity.retain_with_caller::<T>(caller);
|
||||||
@ -244,7 +244,7 @@ pub fn despawn() -> impl EntityCommand {
|
|||||||
/// An [`EntityCommand`] that creates an [`Observer`](crate::observer::Observer)
|
/// An [`EntityCommand`] that creates an [`Observer`](crate::observer::Observer)
|
||||||
/// listening for events of type `E` targeting an entity
|
/// listening for events of type `E` targeting an entity
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn observe<E: EntityEvent, B: Bundle, M>(
|
pub fn observe<E: EntityEvent, B: StaticBundle, M>(
|
||||||
observer: impl IntoObserverSystem<E, B, M>,
|
observer: impl IntoObserverSystem<E, B, M>,
|
||||||
) -> impl EntityCommand {
|
) -> impl EntityCommand {
|
||||||
let caller = MaybeLocation::caller();
|
let caller = MaybeLocation::caller();
|
||||||
@ -304,7 +304,7 @@ pub fn clone_with_opt_in(
|
|||||||
|
|
||||||
/// An [`EntityCommand`] that clones the specified components of an entity
|
/// An [`EntityCommand`] that clones the specified components of an entity
|
||||||
/// and inserts them into another entity.
|
/// and inserts them into another entity.
|
||||||
pub fn clone_components<B: Bundle>(target: Entity) -> impl EntityCommand {
|
pub fn clone_components<B: StaticBundle>(target: Entity) -> impl EntityCommand {
|
||||||
move |mut entity: EntityWorldMut| {
|
move |mut entity: EntityWorldMut| {
|
||||||
entity.clone_components::<B>(target);
|
entity.clone_components::<B>(target);
|
||||||
}
|
}
|
||||||
@ -324,7 +324,7 @@ pub fn clone_components<B: Bundle>(target: Entity) -> impl EntityCommand {
|
|||||||
///
|
///
|
||||||
/// [`Ignore`]: crate::component::ComponentCloneBehavior::Ignore
|
/// [`Ignore`]: crate::component::ComponentCloneBehavior::Ignore
|
||||||
/// [`Custom`]: crate::component::ComponentCloneBehavior::Custom
|
/// [`Custom`]: crate::component::ComponentCloneBehavior::Custom
|
||||||
pub fn move_components<B: Bundle>(target: Entity) -> impl EntityCommand {
|
pub fn move_components<B: StaticBundle>(target: Entity) -> impl EntityCommand {
|
||||||
move |mut entity: EntityWorldMut| {
|
move |mut entity: EntityWorldMut| {
|
||||||
entity.move_components::<B>(target);
|
entity.move_components::<B>(target);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,7 +15,7 @@ use core::marker::PhantomData;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
self as bevy_ecs,
|
self as bevy_ecs,
|
||||||
bundle::{Bundle, InsertMode, NoBundleEffect},
|
bundle::{Bundle, InsertMode, NoBundleEffect, StaticBundle},
|
||||||
change_detection::{MaybeLocation, Mut},
|
change_detection::{MaybeLocation, Mut},
|
||||||
component::{Component, ComponentId, Mutable},
|
component::{Component, ComponentId, Mutable},
|
||||||
entity::{Entities, Entity, EntityClonerBuilder, EntityDoesNotExistError, OptIn, OptOut},
|
entity::{Entities, Entity, EntityClonerBuilder, EntityDoesNotExistError, OptIn, OptOut},
|
||||||
@ -533,7 +533,7 @@ impl<'w, 's> Commands<'w, 's> {
|
|||||||
pub fn spawn_batch<I>(&mut self, batch: I)
|
pub fn spawn_batch<I>(&mut self, batch: I)
|
||||||
where
|
where
|
||||||
I: IntoIterator + Send + Sync + 'static,
|
I: IntoIterator + Send + Sync + 'static,
|
||||||
I::Item: Bundle<Effect: NoBundleEffect>,
|
I::Item: Bundle<Effect: NoBundleEffect> + StaticBundle,
|
||||||
{
|
{
|
||||||
self.queue(command::spawn_batch(batch));
|
self.queue(command::spawn_batch(batch));
|
||||||
}
|
}
|
||||||
@ -686,7 +686,7 @@ impl<'w, 's> Commands<'w, 's> {
|
|||||||
pub fn insert_batch<I, B>(&mut self, batch: I)
|
pub fn insert_batch<I, B>(&mut self, batch: I)
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
|
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
|
||||||
B: Bundle<Effect: NoBundleEffect>,
|
B: Bundle<Effect: NoBundleEffect> + StaticBundle,
|
||||||
{
|
{
|
||||||
self.queue(command::insert_batch(batch, InsertMode::Replace));
|
self.queue(command::insert_batch(batch, InsertMode::Replace));
|
||||||
}
|
}
|
||||||
@ -717,7 +717,7 @@ impl<'w, 's> Commands<'w, 's> {
|
|||||||
pub fn insert_batch_if_new<I, B>(&mut self, batch: I)
|
pub fn insert_batch_if_new<I, B>(&mut self, batch: I)
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
|
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
|
||||||
B: Bundle<Effect: NoBundleEffect>,
|
B: Bundle<Effect: NoBundleEffect> + StaticBundle,
|
||||||
{
|
{
|
||||||
self.queue(command::insert_batch(batch, InsertMode::Keep));
|
self.queue(command::insert_batch(batch, InsertMode::Keep));
|
||||||
}
|
}
|
||||||
@ -747,7 +747,7 @@ impl<'w, 's> Commands<'w, 's> {
|
|||||||
pub fn try_insert_batch<I, B>(&mut self, batch: I)
|
pub fn try_insert_batch<I, B>(&mut self, batch: I)
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
|
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
|
||||||
B: Bundle<Effect: NoBundleEffect>,
|
B: Bundle<Effect: NoBundleEffect> + StaticBundle,
|
||||||
{
|
{
|
||||||
self.queue(command::insert_batch(batch, InsertMode::Replace).handle_error_with(warn));
|
self.queue(command::insert_batch(batch, InsertMode::Replace).handle_error_with(warn));
|
||||||
}
|
}
|
||||||
@ -778,7 +778,7 @@ impl<'w, 's> Commands<'w, 's> {
|
|||||||
pub fn try_insert_batch_if_new<I, B>(&mut self, batch: I)
|
pub fn try_insert_batch_if_new<I, B>(&mut self, batch: I)
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
|
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
|
||||||
B: Bundle<Effect: NoBundleEffect>,
|
B: Bundle<Effect: NoBundleEffect> + StaticBundle,
|
||||||
{
|
{
|
||||||
self.queue(command::insert_batch(batch, InsertMode::Keep).handle_error_with(warn));
|
self.queue(command::insert_batch(batch, InsertMode::Keep).handle_error_with(warn));
|
||||||
}
|
}
|
||||||
@ -1117,7 +1117,7 @@ impl<'w, 's> Commands<'w, 's> {
|
|||||||
/// Panics if the given system is an exclusive system.
|
/// Panics if the given system is an exclusive system.
|
||||||
///
|
///
|
||||||
/// [`On`]: crate::observer::On
|
/// [`On`]: crate::observer::On
|
||||||
pub fn add_observer<E: Event, B: Bundle, M>(
|
pub fn add_observer<E: Event, B: StaticBundle, M>(
|
||||||
&mut self,
|
&mut self,
|
||||||
observer: impl IntoObserverSystem<E, B, M>,
|
observer: impl IntoObserverSystem<E, B, M>,
|
||||||
) -> EntityCommands {
|
) -> EntityCommands {
|
||||||
@ -1642,7 +1642,7 @@ impl<'a> EntityCommands<'a> {
|
|||||||
/// # bevy_ecs::system::assert_is_system(remove_combat_stats_system);
|
/// # bevy_ecs::system::assert_is_system(remove_combat_stats_system);
|
||||||
/// ```
|
/// ```
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn remove<B: Bundle>(&mut self) -> &mut Self {
|
pub fn remove<B: StaticBundle>(&mut self) -> &mut Self {
|
||||||
self.queue_handled(entity_command::remove::<B>(), warn)
|
self.queue_handled(entity_command::remove::<B>(), warn)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1678,7 +1678,7 @@ impl<'a> EntityCommands<'a> {
|
|||||||
/// # bevy_ecs::system::assert_is_system(remove_combat_stats_system);
|
/// # bevy_ecs::system::assert_is_system(remove_combat_stats_system);
|
||||||
/// ```
|
/// ```
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn remove_if<B: Bundle>(&mut self, condition: impl FnOnce() -> bool) -> &mut Self {
|
pub fn remove_if<B: StaticBundle>(&mut self, condition: impl FnOnce() -> bool) -> &mut Self {
|
||||||
if condition() {
|
if condition() {
|
||||||
self.remove::<B>()
|
self.remove::<B>()
|
||||||
} else {
|
} else {
|
||||||
@ -1695,7 +1695,10 @@ impl<'a> EntityCommands<'a> {
|
|||||||
/// If the entity does not exist when this command is executed,
|
/// If the entity does not exist when this command is executed,
|
||||||
/// the resulting error will be ignored.
|
/// the resulting error will be ignored.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn try_remove_if<B: Bundle>(&mut self, condition: impl FnOnce() -> bool) -> &mut Self {
|
pub fn try_remove_if<B: StaticBundle>(
|
||||||
|
&mut self,
|
||||||
|
condition: impl FnOnce() -> bool,
|
||||||
|
) -> &mut Self {
|
||||||
if condition() {
|
if condition() {
|
||||||
self.try_remove::<B>()
|
self.try_remove::<B>()
|
||||||
} else {
|
} else {
|
||||||
@ -1743,7 +1746,7 @@ impl<'a> EntityCommands<'a> {
|
|||||||
/// }
|
/// }
|
||||||
/// # bevy_ecs::system::assert_is_system(remove_combat_stats_system);
|
/// # bevy_ecs::system::assert_is_system(remove_combat_stats_system);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn try_remove<B: Bundle>(&mut self) -> &mut Self {
|
pub fn try_remove<B: StaticBundle>(&mut self) -> &mut Self {
|
||||||
self.queue_silenced(entity_command::remove::<B>())
|
self.queue_silenced(entity_command::remove::<B>())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1775,7 +1778,7 @@ impl<'a> EntityCommands<'a> {
|
|||||||
/// # bevy_ecs::system::assert_is_system(remove_with_requires_system);
|
/// # bevy_ecs::system::assert_is_system(remove_with_requires_system);
|
||||||
/// ```
|
/// ```
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn remove_with_requires<B: Bundle>(&mut self) -> &mut Self {
|
pub fn remove_with_requires<B: StaticBundle>(&mut self) -> &mut Self {
|
||||||
self.queue(entity_command::remove_with_requires::<B>())
|
self.queue(entity_command::remove_with_requires::<B>())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1972,7 +1975,7 @@ impl<'a> EntityCommands<'a> {
|
|||||||
/// # bevy_ecs::system::assert_is_system(remove_combat_stats_system);
|
/// # bevy_ecs::system::assert_is_system(remove_combat_stats_system);
|
||||||
/// ```
|
/// ```
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn retain<B: Bundle>(&mut self) -> &mut Self {
|
pub fn retain<B: StaticBundle>(&mut self) -> &mut Self {
|
||||||
self.queue(entity_command::retain::<B>())
|
self.queue(entity_command::retain::<B>())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2000,7 +2003,7 @@ impl<'a> EntityCommands<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`Observer`] listening for events of type `E` targeting this entity.
|
/// Creates an [`Observer`] listening for events of type `E` targeting this entity.
|
||||||
pub fn observe<E: EntityEvent, B: Bundle, M>(
|
pub fn observe<E: EntityEvent, B: StaticBundle, M>(
|
||||||
&mut self,
|
&mut self,
|
||||||
observer: impl IntoObserverSystem<E, B, M>,
|
observer: impl IntoObserverSystem<E, B, M>,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
@ -2230,7 +2233,7 @@ impl<'a> EntityCommands<'a> {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// The command will panic when applied if the target entity does not exist.
|
/// The command will panic when applied if the target entity does not exist.
|
||||||
pub fn clone_components<B: Bundle>(&mut self, target: Entity) -> &mut Self {
|
pub fn clone_components<B: StaticBundle>(&mut self, target: Entity) -> &mut Self {
|
||||||
self.queue(entity_command::clone_components::<B>(target))
|
self.queue(entity_command::clone_components::<B>(target))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2248,7 +2251,7 @@ impl<'a> EntityCommands<'a> {
|
|||||||
///
|
///
|
||||||
/// [`Ignore`]: crate::component::ComponentCloneBehavior::Ignore
|
/// [`Ignore`]: crate::component::ComponentCloneBehavior::Ignore
|
||||||
/// [`Custom`]: crate::component::ComponentCloneBehavior::Custom
|
/// [`Custom`]: crate::component::ComponentCloneBehavior::Custom
|
||||||
pub fn move_components<B: Bundle>(&mut self, target: Entity) -> &mut Self {
|
pub fn move_components<B: StaticBundle>(&mut self, target: Entity) -> &mut Self {
|
||||||
self.queue(entity_command::move_components::<B>(target))
|
self.queue(entity_command::move_components::<B>(target))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use core::ops::{Deref, DerefMut};
|
|||||||
|
|
||||||
use variadics_please::all_tuples;
|
use variadics_please::all_tuples;
|
||||||
|
|
||||||
use crate::{bundle::Bundle, prelude::On, system::System};
|
use crate::{bundle::StaticBundle, prelude::On, system::System};
|
||||||
|
|
||||||
/// Trait for types that can be used as input to [`System`]s.
|
/// Trait for types that can be used as input to [`System`]s.
|
||||||
///
|
///
|
||||||
@ -222,7 +222,7 @@ impl<'i, T: ?Sized> DerefMut for InMut<'i, T> {
|
|||||||
/// Used for [`ObserverSystem`]s.
|
/// Used for [`ObserverSystem`]s.
|
||||||
///
|
///
|
||||||
/// [`ObserverSystem`]: crate::system::ObserverSystem
|
/// [`ObserverSystem`]: crate::system::ObserverSystem
|
||||||
impl<E: 'static, B: Bundle> SystemInput for On<'_, E, B> {
|
impl<E: 'static, B: StaticBundle> SystemInput for On<'_, E, B> {
|
||||||
type Param<'i> = On<'i, E, B>;
|
type Param<'i> = On<'i, E, B>;
|
||||||
type Inner<'i> = On<'i, E, B>;
|
type Inner<'i> = On<'i, E, B>;
|
||||||
|
|
||||||
|
|||||||
@ -1,17 +1,14 @@
|
|||||||
use crate::{
|
use crate::{bundle::StaticBundle, prelude::On, system::System};
|
||||||
prelude::{Bundle, On},
|
|
||||||
system::System,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::IntoSystem;
|
use super::IntoSystem;
|
||||||
|
|
||||||
/// Implemented for [`System`]s that have [`On`] as the first argument.
|
/// Implemented for [`System`]s that have [`On`] as the first argument.
|
||||||
pub trait ObserverSystem<E: 'static, B: Bundle, Out = ()>:
|
pub trait ObserverSystem<E: 'static, B: StaticBundle, Out = ()>:
|
||||||
System<In = On<'static, E, B>, Out = Out> + Send + 'static
|
System<In = On<'static, E, B>, Out = Out> + Send + 'static
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: 'static, B: Bundle, Out, T> ObserverSystem<E, B, Out> for T where
|
impl<E: 'static, B: StaticBundle, Out, T> ObserverSystem<E, B, Out> for T where
|
||||||
T: System<In = On<'static, E, B>, Out = Out> + Send + 'static
|
T: System<In = On<'static, E, B>, Out = Out> + Send + 'static
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -28,7 +25,7 @@ impl<E: 'static, B: Bundle, Out, T> ObserverSystem<E, B, Out> for T where
|
|||||||
label = "the trait `IntoObserverSystem` is not implemented",
|
label = "the trait `IntoObserverSystem` is not implemented",
|
||||||
note = "for function `ObserverSystem`s, ensure the first argument is `On<T>` and any subsequent ones are `SystemParam`"
|
note = "for function `ObserverSystem`s, ensure the first argument is `On<T>` and any subsequent ones are `SystemParam`"
|
||||||
)]
|
)]
|
||||||
pub trait IntoObserverSystem<E: 'static, B: Bundle, M, Out = ()>: Send + 'static {
|
pub trait IntoObserverSystem<E: 'static, B: StaticBundle, M, Out = ()>: Send + 'static {
|
||||||
/// The type of [`System`] that this instance converts into.
|
/// The type of [`System`] that this instance converts into.
|
||||||
type System: ObserverSystem<E, B, Out>;
|
type System: ObserverSystem<E, B, Out>;
|
||||||
|
|
||||||
@ -41,7 +38,7 @@ where
|
|||||||
S: IntoSystem<On<'static, E, B>, Out, M> + Send + 'static,
|
S: IntoSystem<On<'static, E, B>, Out, M> + Send + 'static,
|
||||||
S::System: ObserverSystem<E, B, Out>,
|
S::System: ObserverSystem<E, B, Out>,
|
||||||
E: 'static,
|
E: 'static,
|
||||||
B: Bundle,
|
B: StaticBundle,
|
||||||
{
|
{
|
||||||
type System = S::System;
|
type System = S::System;
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use crate::{
|
|||||||
archetype::Archetype,
|
archetype::Archetype,
|
||||||
bundle::{
|
bundle::{
|
||||||
Bundle, BundleEffect, BundleFromComponents, BundleInserter, BundleRemover, DynamicBundle,
|
Bundle, BundleEffect, BundleFromComponents, BundleInserter, BundleRemover, DynamicBundle,
|
||||||
InsertMode,
|
InsertMode, StaticBundle,
|
||||||
},
|
},
|
||||||
change_detection::{MaybeLocation, MutUntyped},
|
change_detection::{MaybeLocation, MutUntyped},
|
||||||
component::{
|
component::{
|
||||||
@ -1894,7 +1894,7 @@ impl<'w> EntityWorldMut<'w> {
|
|||||||
let location = self.location();
|
let location = self.location();
|
||||||
let change_tick = self.world.change_tick();
|
let change_tick = self.world.change_tick();
|
||||||
let mut bundle_inserter =
|
let mut bundle_inserter =
|
||||||
BundleInserter::new::<T>(self.world, location.archetype_id, change_tick);
|
BundleInserter::new::<T>(&bundle, self.world, location.archetype_id, change_tick);
|
||||||
// SAFETY: location matches current entity. `T` matches `bundle_info`
|
// SAFETY: location matches current entity. `T` matches `bundle_info`
|
||||||
let (location, after_effect) = unsafe {
|
let (location, after_effect) = unsafe {
|
||||||
bundle_inserter.insert(
|
bundle_inserter.insert(
|
||||||
@ -2052,7 +2052,7 @@ impl<'w> EntityWorldMut<'w> {
|
|||||||
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn take<T: Bundle + BundleFromComponents>(&mut self) -> Option<T> {
|
pub fn take<T: StaticBundle + BundleFromComponents>(&mut self) -> Option<T> {
|
||||||
let location = self.location();
|
let location = self.location();
|
||||||
let entity = self.entity;
|
let entity = self.entity;
|
||||||
|
|
||||||
@ -2108,12 +2108,15 @@ impl<'w> EntityWorldMut<'w> {
|
|||||||
///
|
///
|
||||||
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn remove<T: Bundle>(&mut self) -> &mut Self {
|
pub fn remove<T: StaticBundle>(&mut self) -> &mut Self {
|
||||||
self.remove_with_caller::<T>(MaybeLocation::caller())
|
self.remove_with_caller::<T>(MaybeLocation::caller())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn remove_with_caller<T: Bundle>(&mut self, caller: MaybeLocation) -> &mut Self {
|
pub(crate) fn remove_with_caller<T: StaticBundle>(
|
||||||
|
&mut self,
|
||||||
|
caller: MaybeLocation,
|
||||||
|
) -> &mut Self {
|
||||||
let location = self.location();
|
let location = self.location();
|
||||||
|
|
||||||
let Some(mut remover) =
|
let Some(mut remover) =
|
||||||
@ -2145,11 +2148,11 @@ impl<'w> EntityWorldMut<'w> {
|
|||||||
///
|
///
|
||||||
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn remove_with_requires<T: Bundle>(&mut self) -> &mut Self {
|
pub fn remove_with_requires<T: StaticBundle>(&mut self) -> &mut Self {
|
||||||
self.remove_with_requires_with_caller::<T>(MaybeLocation::caller())
|
self.remove_with_requires_with_caller::<T>(MaybeLocation::caller())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn remove_with_requires_with_caller<T: Bundle>(
|
pub(crate) fn remove_with_requires_with_caller<T: StaticBundle>(
|
||||||
&mut self,
|
&mut self,
|
||||||
caller: MaybeLocation,
|
caller: MaybeLocation,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
@ -2193,12 +2196,15 @@ impl<'w> EntityWorldMut<'w> {
|
|||||||
///
|
///
|
||||||
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn retain<T: Bundle>(&mut self) -> &mut Self {
|
pub fn retain<T: StaticBundle>(&mut self) -> &mut Self {
|
||||||
self.retain_with_caller::<T>(MaybeLocation::caller())
|
self.retain_with_caller::<T>(MaybeLocation::caller())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn retain_with_caller<T: Bundle>(&mut self, caller: MaybeLocation) -> &mut Self {
|
pub(crate) fn retain_with_caller<T: StaticBundle>(
|
||||||
|
&mut self,
|
||||||
|
caller: MaybeLocation,
|
||||||
|
) -> &mut Self {
|
||||||
let old_location = self.location();
|
let old_location = self.location();
|
||||||
let archetypes = &mut self.world.archetypes;
|
let archetypes = &mut self.world.archetypes;
|
||||||
let storages = &mut self.world.storages;
|
let storages = &mut self.world.storages;
|
||||||
@ -2210,7 +2216,7 @@ impl<'w> EntityWorldMut<'w> {
|
|||||||
let retained_bundle = self
|
let retained_bundle = self
|
||||||
.world
|
.world
|
||||||
.bundles
|
.bundles
|
||||||
.register_info::<T>(&mut registrator, storages);
|
.register_static_info::<T>(&mut registrator, storages);
|
||||||
// SAFETY: `retained_bundle` exists as we just initialized it.
|
// SAFETY: `retained_bundle` exists as we just initialized it.
|
||||||
let retained_bundle_info = unsafe { self.world.bundles.get_unchecked(retained_bundle) };
|
let retained_bundle_info = unsafe { self.world.bundles.get_unchecked(retained_bundle) };
|
||||||
let old_archetype = &mut archetypes[old_location.archetype_id];
|
let old_archetype = &mut archetypes[old_location.archetype_id];
|
||||||
@ -2708,14 +2714,14 @@ impl<'w> EntityWorldMut<'w> {
|
|||||||
///
|
///
|
||||||
/// Panics if the given system is an exclusive system.
|
/// Panics if the given system is an exclusive system.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn observe<E: EntityEvent, B: Bundle, M>(
|
pub fn observe<E: EntityEvent, B: StaticBundle, M>(
|
||||||
&mut self,
|
&mut self,
|
||||||
observer: impl IntoObserverSystem<E, B, M>,
|
observer: impl IntoObserverSystem<E, B, M>,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.observe_with_caller(observer, MaybeLocation::caller())
|
self.observe_with_caller(observer, MaybeLocation::caller())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn observe_with_caller<E: EntityEvent, B: Bundle, M>(
|
pub(crate) fn observe_with_caller<E: EntityEvent, B: StaticBundle, M>(
|
||||||
&mut self,
|
&mut self,
|
||||||
observer: impl IntoObserverSystem<E, B, M>,
|
observer: impl IntoObserverSystem<E, B, M>,
|
||||||
caller: MaybeLocation,
|
caller: MaybeLocation,
|
||||||
@ -2945,7 +2951,7 @@ impl<'w> EntityWorldMut<'w> {
|
|||||||
///
|
///
|
||||||
/// - If this entity has been despawned while this `EntityWorldMut` is still alive.
|
/// - If this entity has been despawned while this `EntityWorldMut` is still alive.
|
||||||
/// - If the target entity does not exist.
|
/// - If the target entity does not exist.
|
||||||
pub fn clone_components<B: Bundle>(&mut self, target: Entity) -> &mut Self {
|
pub fn clone_components<B: StaticBundle>(&mut self, target: Entity) -> &mut Self {
|
||||||
self.assert_not_despawned();
|
self.assert_not_despawned();
|
||||||
|
|
||||||
EntityCloner::build_opt_in(self.world)
|
EntityCloner::build_opt_in(self.world)
|
||||||
@ -2967,7 +2973,7 @@ impl<'w> EntityWorldMut<'w> {
|
|||||||
///
|
///
|
||||||
/// - If this entity has been despawned while this `EntityWorldMut` is still alive.
|
/// - If this entity has been despawned while this `EntityWorldMut` is still alive.
|
||||||
/// - If the target entity does not exist.
|
/// - If the target entity does not exist.
|
||||||
pub fn move_components<B: Bundle>(&mut self, target: Entity) -> &mut Self {
|
pub fn move_components<B: StaticBundle>(&mut self, target: Entity) -> &mut Self {
|
||||||
self.assert_not_despawned();
|
self.assert_not_despawned();
|
||||||
|
|
||||||
EntityCloner::build_opt_in(self.world)
|
EntityCloner::build_opt_in(self.world)
|
||||||
@ -3631,7 +3637,7 @@ impl<'a> From<&'a EntityWorldMut<'_>> for FilteredEntityRef<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, B: Bundle> From<&'a EntityRefExcept<'_, B>> for FilteredEntityRef<'a> {
|
impl<'a, B: StaticBundle> From<&'a EntityRefExcept<'_, B>> for FilteredEntityRef<'a> {
|
||||||
fn from(value: &'a EntityRefExcept<'_, B>) -> Self {
|
fn from(value: &'a EntityRefExcept<'_, B>) -> Self {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - The FilteredEntityRef has the same component access as the given EntityRefExcept.
|
// - The FilteredEntityRef has the same component access as the given EntityRefExcept.
|
||||||
@ -3979,7 +3985,7 @@ impl<'a> From<&'a mut EntityWorldMut<'_>> for FilteredEntityMut<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, B: Bundle> From<&'a EntityMutExcept<'_, B>> for FilteredEntityMut<'a> {
|
impl<'a, B: StaticBundle> From<&'a EntityMutExcept<'_, B>> for FilteredEntityMut<'a> {
|
||||||
fn from(value: &'a EntityMutExcept<'_, B>) -> Self {
|
fn from(value: &'a EntityMutExcept<'_, B>) -> Self {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - The FilteredEntityMut has the same component access as the given EntityMutExcept.
|
// - The FilteredEntityMut has the same component access as the given EntityMutExcept.
|
||||||
@ -4053,7 +4059,7 @@ pub enum TryFromFilteredError {
|
|||||||
/// for an explicitly-enumerated set.
|
/// for an explicitly-enumerated set.
|
||||||
pub struct EntityRefExcept<'w, B>
|
pub struct EntityRefExcept<'w, B>
|
||||||
where
|
where
|
||||||
B: Bundle,
|
B: StaticBundle,
|
||||||
{
|
{
|
||||||
entity: UnsafeEntityCell<'w>,
|
entity: UnsafeEntityCell<'w>,
|
||||||
phantom: PhantomData<B>,
|
phantom: PhantomData<B>,
|
||||||
@ -4061,7 +4067,7 @@ where
|
|||||||
|
|
||||||
impl<'w, B> EntityRefExcept<'w, B>
|
impl<'w, B> EntityRefExcept<'w, B>
|
||||||
where
|
where
|
||||||
B: Bundle,
|
B: StaticBundle,
|
||||||
{
|
{
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// Other users of `UnsafeEntityCell` must only have mutable access to the components in `B`.
|
/// Other users of `UnsafeEntityCell` must only have mutable access to the components in `B`.
|
||||||
@ -4222,7 +4228,7 @@ where
|
|||||||
|
|
||||||
impl<'a, B> From<&'a EntityMutExcept<'_, B>> for EntityRefExcept<'a, B>
|
impl<'a, B> From<&'a EntityMutExcept<'_, B>> for EntityRefExcept<'a, B>
|
||||||
where
|
where
|
||||||
B: Bundle,
|
B: StaticBundle,
|
||||||
{
|
{
|
||||||
fn from(entity: &'a EntityMutExcept<'_, B>) -> Self {
|
fn from(entity: &'a EntityMutExcept<'_, B>) -> Self {
|
||||||
// SAFETY: All accesses that `EntityRefExcept` provides are also
|
// SAFETY: All accesses that `EntityRefExcept` provides are also
|
||||||
@ -4231,23 +4237,23 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: Bundle> Clone for EntityRefExcept<'_, B> {
|
impl<B: StaticBundle> Clone for EntityRefExcept<'_, B> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
*self
|
*self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: Bundle> Copy for EntityRefExcept<'_, B> {}
|
impl<B: StaticBundle> Copy for EntityRefExcept<'_, B> {}
|
||||||
|
|
||||||
impl<B: Bundle> PartialEq for EntityRefExcept<'_, B> {
|
impl<B: StaticBundle> PartialEq for EntityRefExcept<'_, B> {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.entity() == other.entity()
|
self.entity() == other.entity()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: Bundle> Eq for EntityRefExcept<'_, B> {}
|
impl<B: StaticBundle> Eq for EntityRefExcept<'_, B> {}
|
||||||
|
|
||||||
impl<B: Bundle> PartialOrd for EntityRefExcept<'_, B> {
|
impl<B: StaticBundle> PartialOrd for EntityRefExcept<'_, B> {
|
||||||
/// [`EntityRefExcept`]'s comparison trait implementations match the underlying [`Entity`],
|
/// [`EntityRefExcept`]'s comparison trait implementations match the underlying [`Entity`],
|
||||||
/// and cannot discern between different worlds.
|
/// and cannot discern between different worlds.
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
@ -4255,26 +4261,26 @@ impl<B: Bundle> PartialOrd for EntityRefExcept<'_, B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: Bundle> Ord for EntityRefExcept<'_, B> {
|
impl<B: StaticBundle> Ord for EntityRefExcept<'_, B> {
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
self.entity().cmp(&other.entity())
|
self.entity().cmp(&other.entity())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: Bundle> Hash for EntityRefExcept<'_, B> {
|
impl<B: StaticBundle> Hash for EntityRefExcept<'_, B> {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.entity().hash(state);
|
self.entity().hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: Bundle> ContainsEntity for EntityRefExcept<'_, B> {
|
impl<B: StaticBundle> ContainsEntity for EntityRefExcept<'_, B> {
|
||||||
fn entity(&self) -> Entity {
|
fn entity(&self) -> Entity {
|
||||||
self.id()
|
self.id()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: This type represents one Entity. We implement the comparison traits based on that Entity.
|
// SAFETY: This type represents one Entity. We implement the comparison traits based on that Entity.
|
||||||
unsafe impl<B: Bundle> EntityEquivalent for EntityRefExcept<'_, B> {}
|
unsafe impl<B: StaticBundle> EntityEquivalent for EntityRefExcept<'_, B> {}
|
||||||
|
|
||||||
/// Provides mutable access to all components of an entity, with the exception
|
/// Provides mutable access to all components of an entity, with the exception
|
||||||
/// of an explicit set.
|
/// of an explicit set.
|
||||||
@ -4286,7 +4292,7 @@ unsafe impl<B: Bundle> EntityEquivalent for EntityRefExcept<'_, B> {}
|
|||||||
/// [`crate::query::Without`] filter.
|
/// [`crate::query::Without`] filter.
|
||||||
pub struct EntityMutExcept<'w, B>
|
pub struct EntityMutExcept<'w, B>
|
||||||
where
|
where
|
||||||
B: Bundle,
|
B: StaticBundle,
|
||||||
{
|
{
|
||||||
entity: UnsafeEntityCell<'w>,
|
entity: UnsafeEntityCell<'w>,
|
||||||
phantom: PhantomData<B>,
|
phantom: PhantomData<B>,
|
||||||
@ -4294,7 +4300,7 @@ where
|
|||||||
|
|
||||||
impl<'w, B> EntityMutExcept<'w, B>
|
impl<'w, B> EntityMutExcept<'w, B>
|
||||||
where
|
where
|
||||||
B: Bundle,
|
B: StaticBundle,
|
||||||
{
|
{
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// Other users of `UnsafeEntityCell` must not have access to any components not in `B`.
|
/// Other users of `UnsafeEntityCell` must not have access to any components not in `B`.
|
||||||
@ -4454,15 +4460,15 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: Bundle> PartialEq for EntityMutExcept<'_, B> {
|
impl<B: StaticBundle> PartialEq for EntityMutExcept<'_, B> {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.entity() == other.entity()
|
self.entity() == other.entity()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: Bundle> Eq for EntityMutExcept<'_, B> {}
|
impl<B: StaticBundle> Eq for EntityMutExcept<'_, B> {}
|
||||||
|
|
||||||
impl<B: Bundle> PartialOrd for EntityMutExcept<'_, B> {
|
impl<B: StaticBundle> PartialOrd for EntityMutExcept<'_, B> {
|
||||||
/// [`EntityMutExcept`]'s comparison trait implementations match the underlying [`Entity`],
|
/// [`EntityMutExcept`]'s comparison trait implementations match the underlying [`Entity`],
|
||||||
/// and cannot discern between different worlds.
|
/// and cannot discern between different worlds.
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
@ -4470,30 +4476,30 @@ impl<B: Bundle> PartialOrd for EntityMutExcept<'_, B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: Bundle> Ord for EntityMutExcept<'_, B> {
|
impl<B: StaticBundle> Ord for EntityMutExcept<'_, B> {
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
self.entity().cmp(&other.entity())
|
self.entity().cmp(&other.entity())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: Bundle> Hash for EntityMutExcept<'_, B> {
|
impl<B: StaticBundle> Hash for EntityMutExcept<'_, B> {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.entity().hash(state);
|
self.entity().hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: Bundle> ContainsEntity for EntityMutExcept<'_, B> {
|
impl<B: StaticBundle> ContainsEntity for EntityMutExcept<'_, B> {
|
||||||
fn entity(&self) -> Entity {
|
fn entity(&self) -> Entity {
|
||||||
self.id()
|
self.id()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: This type represents one Entity. We implement the comparison traits based on that Entity.
|
// SAFETY: This type represents one Entity. We implement the comparison traits based on that Entity.
|
||||||
unsafe impl<B: Bundle> EntityEquivalent for EntityMutExcept<'_, B> {}
|
unsafe impl<B: StaticBundle> EntityEquivalent for EntityMutExcept<'_, B> {}
|
||||||
|
|
||||||
fn bundle_contains_component<B>(components: &Components, query_id: ComponentId) -> bool
|
fn bundle_contains_component<B>(components: &Components, query_id: ComponentId) -> bool
|
||||||
where
|
where
|
||||||
B: Bundle,
|
B: StaticBundle,
|
||||||
{
|
{
|
||||||
let mut found = false;
|
let mut found = false;
|
||||||
B::get_component_ids(components, &mut |maybe_id| {
|
B::get_component_ids(components, &mut |maybe_id| {
|
||||||
|
|||||||
@ -40,7 +40,7 @@ use crate::{
|
|||||||
archetype::{ArchetypeId, Archetypes},
|
archetype::{ArchetypeId, Archetypes},
|
||||||
bundle::{
|
bundle::{
|
||||||
Bundle, BundleEffect, BundleInfo, BundleInserter, BundleSpawner, Bundles, InsertMode,
|
Bundle, BundleEffect, BundleInfo, BundleInserter, BundleSpawner, Bundles, InsertMode,
|
||||||
NoBundleEffect,
|
NoBundleEffect, StaticBundle,
|
||||||
},
|
},
|
||||||
change_detection::{MaybeLocation, MutUntyped, TicksMut},
|
change_detection::{MaybeLocation, MutUntyped, TicksMut},
|
||||||
component::{
|
component::{
|
||||||
@ -1173,7 +1173,7 @@ impl World {
|
|||||||
self.flush();
|
self.flush();
|
||||||
let change_tick = self.change_tick();
|
let change_tick = self.change_tick();
|
||||||
let entity = self.entities.alloc();
|
let entity = self.entities.alloc();
|
||||||
let mut bundle_spawner = BundleSpawner::new::<B>(self, change_tick);
|
let mut bundle_spawner = BundleSpawner::new(&bundle, self, change_tick);
|
||||||
// SAFETY: bundle's type matches `bundle_info`, entity is allocated but non-existent
|
// SAFETY: bundle's type matches `bundle_info`, entity is allocated but non-existent
|
||||||
let (entity_location, after_effect) =
|
let (entity_location, after_effect) =
|
||||||
unsafe { bundle_spawner.spawn_non_existent(entity, bundle, caller) };
|
unsafe { bundle_spawner.spawn_non_existent(entity, bundle, caller) };
|
||||||
@ -1239,7 +1239,7 @@ impl World {
|
|||||||
pub fn spawn_batch<I>(&mut self, iter: I) -> SpawnBatchIter<'_, I::IntoIter>
|
pub fn spawn_batch<I>(&mut self, iter: I) -> SpawnBatchIter<'_, I::IntoIter>
|
||||||
where
|
where
|
||||||
I: IntoIterator,
|
I: IntoIterator,
|
||||||
I::Item: Bundle<Effect: NoBundleEffect>,
|
I::Item: Bundle<Effect: NoBundleEffect> + StaticBundle,
|
||||||
{
|
{
|
||||||
SpawnBatchIter::new(self, iter.into_iter(), MaybeLocation::caller())
|
SpawnBatchIter::new(self, iter.into_iter(), MaybeLocation::caller())
|
||||||
}
|
}
|
||||||
@ -2255,7 +2255,7 @@ impl World {
|
|||||||
where
|
where
|
||||||
I: IntoIterator,
|
I: IntoIterator,
|
||||||
I::IntoIter: Iterator<Item = (Entity, B)>,
|
I::IntoIter: Iterator<Item = (Entity, B)>,
|
||||||
B: Bundle<Effect: NoBundleEffect>,
|
B: Bundle<Effect: NoBundleEffect> + StaticBundle,
|
||||||
{
|
{
|
||||||
self.insert_batch_with_caller(batch, InsertMode::Replace, MaybeLocation::caller());
|
self.insert_batch_with_caller(batch, InsertMode::Replace, MaybeLocation::caller());
|
||||||
}
|
}
|
||||||
@ -2280,7 +2280,7 @@ impl World {
|
|||||||
where
|
where
|
||||||
I: IntoIterator,
|
I: IntoIterator,
|
||||||
I::IntoIter: Iterator<Item = (Entity, B)>,
|
I::IntoIter: Iterator<Item = (Entity, B)>,
|
||||||
B: Bundle<Effect: NoBundleEffect>,
|
B: Bundle<Effect: NoBundleEffect> + StaticBundle,
|
||||||
{
|
{
|
||||||
self.insert_batch_with_caller(batch, InsertMode::Keep, MaybeLocation::caller());
|
self.insert_batch_with_caller(batch, InsertMode::Keep, MaybeLocation::caller());
|
||||||
}
|
}
|
||||||
@ -2299,7 +2299,7 @@ impl World {
|
|||||||
) where
|
) where
|
||||||
I: IntoIterator,
|
I: IntoIterator,
|
||||||
I::IntoIter: Iterator<Item = (Entity, B)>,
|
I::IntoIter: Iterator<Item = (Entity, B)>,
|
||||||
B: Bundle<Effect: NoBundleEffect>,
|
B: Bundle<Effect: NoBundleEffect> + StaticBundle,
|
||||||
{
|
{
|
||||||
struct InserterArchetypeCache<'w> {
|
struct InserterArchetypeCache<'w> {
|
||||||
inserter: BundleInserter<'w>,
|
inserter: BundleInserter<'w>,
|
||||||
@ -2313,7 +2313,7 @@ impl World {
|
|||||||
unsafe { ComponentsRegistrator::new(&mut self.components, &mut self.component_ids) };
|
unsafe { ComponentsRegistrator::new(&mut self.components, &mut self.component_ids) };
|
||||||
let bundle_id = self
|
let bundle_id = self
|
||||||
.bundles
|
.bundles
|
||||||
.register_info::<B>(&mut registrator, &mut self.storages);
|
.register_static_info::<B>(&mut registrator, &mut self.storages);
|
||||||
|
|
||||||
let mut batch_iter = batch.into_iter();
|
let mut batch_iter = batch.into_iter();
|
||||||
|
|
||||||
@ -2398,7 +2398,7 @@ impl World {
|
|||||||
where
|
where
|
||||||
I: IntoIterator,
|
I: IntoIterator,
|
||||||
I::IntoIter: Iterator<Item = (Entity, B)>,
|
I::IntoIter: Iterator<Item = (Entity, B)>,
|
||||||
B: Bundle<Effect: NoBundleEffect>,
|
B: Bundle<Effect: NoBundleEffect> + StaticBundle,
|
||||||
{
|
{
|
||||||
self.try_insert_batch_with_caller(batch, InsertMode::Replace, MaybeLocation::caller())
|
self.try_insert_batch_with_caller(batch, InsertMode::Replace, MaybeLocation::caller())
|
||||||
}
|
}
|
||||||
@ -2420,7 +2420,7 @@ impl World {
|
|||||||
where
|
where
|
||||||
I: IntoIterator,
|
I: IntoIterator,
|
||||||
I::IntoIter: Iterator<Item = (Entity, B)>,
|
I::IntoIter: Iterator<Item = (Entity, B)>,
|
||||||
B: Bundle<Effect: NoBundleEffect>,
|
B: Bundle<Effect: NoBundleEffect> + StaticBundle,
|
||||||
{
|
{
|
||||||
self.try_insert_batch_with_caller(batch, InsertMode::Keep, MaybeLocation::caller())
|
self.try_insert_batch_with_caller(batch, InsertMode::Keep, MaybeLocation::caller())
|
||||||
}
|
}
|
||||||
@ -2444,7 +2444,7 @@ impl World {
|
|||||||
where
|
where
|
||||||
I: IntoIterator,
|
I: IntoIterator,
|
||||||
I::IntoIter: Iterator<Item = (Entity, B)>,
|
I::IntoIter: Iterator<Item = (Entity, B)>,
|
||||||
B: Bundle<Effect: NoBundleEffect>,
|
B: Bundle<Effect: NoBundleEffect> + StaticBundle,
|
||||||
{
|
{
|
||||||
struct InserterArchetypeCache<'w> {
|
struct InserterArchetypeCache<'w> {
|
||||||
inserter: BundleInserter<'w>,
|
inserter: BundleInserter<'w>,
|
||||||
@ -2458,7 +2458,7 @@ impl World {
|
|||||||
unsafe { ComponentsRegistrator::new(&mut self.components, &mut self.component_ids) };
|
unsafe { ComponentsRegistrator::new(&mut self.components, &mut self.component_ids) };
|
||||||
let bundle_id = self
|
let bundle_id = self
|
||||||
.bundles
|
.bundles
|
||||||
.register_info::<B>(&mut registrator, &mut self.storages);
|
.register_static_info::<B>(&mut registrator, &mut self.storages);
|
||||||
|
|
||||||
let mut invalid_entities = Vec::<Entity>::new();
|
let mut invalid_entities = Vec::<Entity>::new();
|
||||||
let mut batch_iter = batch.into_iter();
|
let mut batch_iter = batch.into_iter();
|
||||||
@ -3074,13 +3074,13 @@ impl World {
|
|||||||
/// This is largely equivalent to calling [`register_component`](Self::register_component) on each
|
/// This is largely equivalent to calling [`register_component`](Self::register_component) on each
|
||||||
/// component in the bundle.
|
/// component in the bundle.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn register_bundle<B: Bundle>(&mut self) -> &BundleInfo {
|
pub fn register_bundle<B: StaticBundle>(&mut self) -> &BundleInfo {
|
||||||
// SAFETY: These come from the same world. `Self.components_registrator` can't be used since we borrow other fields too.
|
// SAFETY: These come from the same world. `Self.components_registrator` can't be used since we borrow other fields too.
|
||||||
let mut registrator =
|
let mut registrator =
|
||||||
unsafe { ComponentsRegistrator::new(&mut self.components, &mut self.component_ids) };
|
unsafe { ComponentsRegistrator::new(&mut self.components, &mut self.component_ids) };
|
||||||
let id = self
|
let id = self
|
||||||
.bundles
|
.bundles
|
||||||
.register_info::<B>(&mut registrator, &mut self.storages);
|
.register_static_info::<B>(&mut registrator, &mut self.storages);
|
||||||
// SAFETY: We just initialized the bundle so its id should definitely be valid.
|
// SAFETY: We just initialized the bundle so its id should definitely be valid.
|
||||||
unsafe { self.bundles.get(id).debug_checked_unwrap() }
|
unsafe { self.bundles.get(id).debug_checked_unwrap() }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
bundle::{Bundle, BundleSpawner, NoBundleEffect},
|
bundle::{Bundle, BundleSpawner, NoBundleEffect, StaticBundle},
|
||||||
change_detection::MaybeLocation,
|
change_detection::MaybeLocation,
|
||||||
entity::{Entity, EntitySetIterator},
|
entity::{Entity, EntitySetIterator},
|
||||||
world::World,
|
world::World,
|
||||||
@ -13,7 +13,7 @@ use core::iter::FusedIterator;
|
|||||||
pub struct SpawnBatchIter<'w, I>
|
pub struct SpawnBatchIter<'w, I>
|
||||||
where
|
where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
I::Item: Bundle,
|
I::Item: Bundle + StaticBundle,
|
||||||
{
|
{
|
||||||
inner: I,
|
inner: I,
|
||||||
spawner: BundleSpawner<'w>,
|
spawner: BundleSpawner<'w>,
|
||||||
@ -23,7 +23,7 @@ where
|
|||||||
impl<'w, I> SpawnBatchIter<'w, I>
|
impl<'w, I> SpawnBatchIter<'w, I>
|
||||||
where
|
where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
I::Item: Bundle<Effect: NoBundleEffect>,
|
I::Item: Bundle<Effect: NoBundleEffect> + StaticBundle,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
@ -38,7 +38,7 @@ where
|
|||||||
let length = upper.unwrap_or(lower);
|
let length = upper.unwrap_or(lower);
|
||||||
world.entities.reserve(length as u32);
|
world.entities.reserve(length as u32);
|
||||||
|
|
||||||
let mut spawner = BundleSpawner::new::<I::Item>(world, change_tick);
|
let mut spawner = BundleSpawner::new_static::<I::Item>(world, change_tick);
|
||||||
spawner.reserve_storage(length);
|
spawner.reserve_storage(length);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
@ -52,7 +52,7 @@ where
|
|||||||
impl<I> Drop for SpawnBatchIter<'_, I>
|
impl<I> Drop for SpawnBatchIter<'_, I>
|
||||||
where
|
where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
I::Item: Bundle,
|
I::Item: Bundle + StaticBundle,
|
||||||
{
|
{
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// Iterate through self in order to spawn remaining bundles.
|
// Iterate through self in order to spawn remaining bundles.
|
||||||
@ -66,7 +66,7 @@ where
|
|||||||
impl<I> Iterator for SpawnBatchIter<'_, I>
|
impl<I> Iterator for SpawnBatchIter<'_, I>
|
||||||
where
|
where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
I::Item: Bundle,
|
I::Item: Bundle + StaticBundle,
|
||||||
{
|
{
|
||||||
type Item = Entity;
|
type Item = Entity;
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ where
|
|||||||
impl<I, T> ExactSizeIterator for SpawnBatchIter<'_, I>
|
impl<I, T> ExactSizeIterator for SpawnBatchIter<'_, I>
|
||||||
where
|
where
|
||||||
I: ExactSizeIterator<Item = T>,
|
I: ExactSizeIterator<Item = T>,
|
||||||
T: Bundle,
|
T: Bundle + StaticBundle,
|
||||||
{
|
{
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
self.inner.len()
|
self.inner.len()
|
||||||
@ -94,7 +94,7 @@ where
|
|||||||
impl<I, T> FusedIterator for SpawnBatchIter<'_, I>
|
impl<I, T> FusedIterator for SpawnBatchIter<'_, I>
|
||||||
where
|
where
|
||||||
I: FusedIterator<Item = T>,
|
I: FusedIterator<Item = T>,
|
||||||
T: Bundle,
|
T: Bundle + StaticBundle,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,6 +102,6 @@ where
|
|||||||
unsafe impl<I: Iterator, T> EntitySetIterator for SpawnBatchIter<'_, I>
|
unsafe impl<I: Iterator, T> EntitySetIterator for SpawnBatchIter<'_, I>
|
||||||
where
|
where
|
||||||
I: FusedIterator<Item = T>,
|
I: FusedIterator<Item = T>,
|
||||||
T: Bundle,
|
T: Bundle + StaticBundle,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ use crate::{
|
|||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_camera::visibility::ViewVisibility;
|
use bevy_camera::visibility::ViewVisibility;
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
bundle::NoBundleEffect,
|
bundle::{NoBundleEffect, StaticBundle},
|
||||||
component::Component,
|
component::Component,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
query::{QueryFilter, QueryItem, ReadOnlyQueryData},
|
query::{QueryFilter, QueryItem, ReadOnlyQueryData},
|
||||||
@ -54,7 +54,7 @@ pub trait ExtractComponent: Component {
|
|||||||
///
|
///
|
||||||
/// `Out` has a [`Bundle`] trait bound instead of a [`Component`] trait bound in order to allow use cases
|
/// `Out` has a [`Bundle`] trait bound instead of a [`Component`] trait bound in order to allow use cases
|
||||||
/// such as tuples of components as output.
|
/// such as tuples of components as output.
|
||||||
type Out: Bundle<Effect: NoBundleEffect>;
|
type Out: Bundle<Effect: NoBundleEffect> + StaticBundle;
|
||||||
|
|
||||||
// TODO: https://github.com/rust-lang/rust/issues/29661
|
// TODO: https://github.com/rust-lang/rust/issues/29661
|
||||||
// type Out: Component = Self;
|
// type Out: Component = Self;
|
||||||
|
|||||||
55
release-content/migration-guides/static-bundle-split.md
Normal file
55
release-content/migration-guides/static-bundle-split.md
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
---
|
||||||
|
title: \`StaticBundle` has been split off from `Bundle`
|
||||||
|
pull_requests: [19491]
|
||||||
|
---
|
||||||
|
|
||||||
|
The `StaticBundle` trait has been split off from the `Bundle` trait to avoid conflating the concept of a type whose values can be inserted into an entity (`Bundle`) with the concept of a statically known set of components (`StaticBundle`). This required the update of existing APIs that were using `Bundle` as a statically known set of components to use `StaticBundle` instead.
|
||||||
|
|
||||||
|
Changes for most users will be zero or pretty minimal, since `#[derive(Bundle)]` will automatically derive `StaticBundle` and most types that implemented `Bundle` will now also implement `StaticBundle`. The main exception will be generic APIs or types, which now will need to update or add a bound on `StaticBundle`. For example:
|
||||||
|
|
||||||
|
```rs
|
||||||
|
// 0.16
|
||||||
|
#[derive(Bundle)]
|
||||||
|
struct MyBundleWrapper<T: Bundle> {
|
||||||
|
inner: T
|
||||||
|
}
|
||||||
|
|
||||||
|
fn my_register_bundle<T: Bundle>(world: &mut World) {
|
||||||
|
world.register_bundle::<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 0.17
|
||||||
|
#[derive(Bundle)]
|
||||||
|
struct MyBundleWrapper<T: Bundle + StaticBundle> { // Add a StaticBundle bound
|
||||||
|
inner: T
|
||||||
|
}
|
||||||
|
|
||||||
|
fn my_register_bundle<T: StaticBundle>(world: &mut World) { // Replace Bundle with StaticBundle
|
||||||
|
world.register_bundle::<T>();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The following APIs now require the `StaticBundle` trait instead of the `Bundle` trait:
|
||||||
|
|
||||||
|
- `World::register_bundle`, which has been renamed to `World::register_static_bundle`
|
||||||
|
- the `B` type parameter of `EntityRefExcept` and `EntityMutExcept`
|
||||||
|
- `EntityClonerBuilder::allow` and `EntityClonerBuilder::deny`
|
||||||
|
- `EntityCommands::clone_components` and `EntityCommands::move_components`
|
||||||
|
- `EntityWorldMut::clone_components` and `EntityWorldMut::move_components`
|
||||||
|
- the `B` type parameter of `IntoObserverSystem`, `Trigger`, `App::add_observer`, `World::add_observer`, `Observer::new`, `Commands::add_observer`, `EntityCommands::observe` and `EntityWorldMut::observe`
|
||||||
|
- `EntityWorldMut::remove_recursive` and `Commands::remove_recursive`
|
||||||
|
- `EntityCommands::remove`, `EntityCommands::remove_if`, `EntityCommands::try_remove_if`, `EntityCommands::try_remove`, `EntityCommands::remove_with_requires`, `EntityWorldMut::remove` and `EntityWorldMut::remove_with_requires`
|
||||||
|
- `EntityWorldMut::take`
|
||||||
|
- `EntityWorldMut::retain` and `EntityCommands::retain`
|
||||||
|
|
||||||
|
The following APIs now require the `StaticBundle` trait in addition to the `Bundle` trait:
|
||||||
|
|
||||||
|
- `Commands::spawn_batch`, `Commands::insert_batch`, `Commands::insert_batch_if_new`, `Commands::try_insert_batch`, `Commands::try_insert_batch_if_new`, `bevy::ecs::command::spawn_batch`, `bevy::ecs::command::insert_batch`, `World::spawn_batch`, `World::insert_batch`, `World::insert_batch_if_new`, `World::try_insert_batch` and `World::try_insert_batch_if_new`
|
||||||
|
- `ReflectBundle::new`, `impl FromType<B>` for `ReflectBundle` and `#[reflect(Bundle)]`
|
||||||
|
- `ExtractComponent::Out`
|
||||||
|
|
||||||
|
Moreover, some APIs have been renamed:
|
||||||
|
|
||||||
|
- `World::register_bundle` has been renamed to `World::register_static_bundle`
|
||||||
|
- the `DynamicBundle` trait has been renamed to `ComponentsFromBundle`
|
||||||
Loading…
Reference in New Issue
Block a user