Skip to content

Stop inserting RelationshipTarget on SpawnRelatedBundle #19726

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion crates/bevy_ecs/src/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2187,7 +2187,8 @@ mod tests {
})
.id();

assert!(world.entity(id).get::<Children>().is_some());
assert!(world.entity(id).get::<B>().is_some());
assert!(world.entity(id).get::<Children>().is_none());
}

#[test]
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_ecs/src/hierarchy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -475,8 +475,8 @@ pub fn validate_parent_has_component<C: Component>(
}
}

/// Returns a [`SpawnRelatedBundle`] that will insert the [`Children`] component, spawn a [`SpawnableList`] of entities with given bundles that
/// relate to the [`Children`] entity via the [`ChildOf`] component, and reserve space in the [`Children`] for each spawned entity.
/// Returns a [`SpawnRelatedBundle`] that will spawn a [`SpawnableList`] of entities with given bundles that
/// relate to the [`Children`] entity via the [`ChildOf`] component.
///
/// Any additional arguments will be interpreted as bundles to be spawned.
///
Expand Down
71 changes: 25 additions & 46 deletions crates/bevy_ecs/src/spawn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,7 @@ macro_rules! spawnable_list_impl {

all_tuples!(spawnable_list_impl, 0, 12, P);

/// A [`Bundle`] that:
/// 1. Contains a [`RelationshipTarget`] component (associated with the given [`Relationship`]). This reserves space for the [`SpawnableList`].
/// 2. Spawns a [`SpawnableList`] of related entities with a given [`Relationship`].
/// A [`Bundle`] that spawns a [`SpawnableList`] of related entities with a given [`Relationship`].
///
/// This is intended to be created using [`SpawnRelated`].
pub struct SpawnRelatedBundle<R: Relationship, L: SpawnableList<R>> {
Expand All @@ -182,50 +180,40 @@ 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 is a blank implementation.
unsafe impl<R: Relationship, L: SpawnableList<R> + Send + Sync + 'static> Bundle
for SpawnRelatedBundle<R, L>
{
fn component_ids(
components: &mut crate::component::ComponentsRegistrator,
ids: &mut impl FnMut(crate::component::ComponentId),
_components: &mut crate::component::ComponentsRegistrator,
_ids: &mut impl FnMut(crate::component::ComponentId),
) {
<R::RelationshipTarget as Bundle>::component_ids(components, ids);
}

fn get_component_ids(
components: &crate::component::Components,
ids: &mut impl FnMut(Option<crate::component::ComponentId>),
_components: &crate::component::Components,
_ids: &mut impl FnMut(Option<crate::component::ComponentId>),
) {
<R::RelationshipTarget as Bundle>::get_component_ids(components, ids);
}

fn register_required_components(
components: &mut crate::component::ComponentsRegistrator,
required_components: &mut crate::component::RequiredComponents,
_components: &mut crate::component::ComponentsRegistrator,
_required_components: &mut crate::component::RequiredComponents,
) {
<R::RelationshipTarget as Bundle>::register_required_components(
components,
required_components,
);
}
}
impl<R: Relationship, L: SpawnableList<R>> DynamicBundle for SpawnRelatedBundle<R, L> {
type Effect = Self;

fn get_components(
self,
func: &mut impl FnMut(crate::component::StorageType, bevy_ptr::OwningPtr<'_>),
_func: &mut impl FnMut(crate::component::StorageType, bevy_ptr::OwningPtr<'_>),
) -> Self::Effect {
<R::RelationshipTarget as RelationshipTarget>::with_capacity(self.list.size_hint())
.get_components(func);
self
}
}

/// A [`Bundle`] that:
/// 1. Contains a [`RelationshipTarget`] component (associated with the given [`Relationship`]). This reserves space for a single entity.
/// 2. Spawns a single related entity containing the given `B` [`Bundle`] and the given [`Relationship`].
/// A [`Bundle`] that spawns a single related entity containing the given `B` [`Bundle`] and the given [`Relationship`].
///
/// This is intended to be created using [`SpawnRelated`].
pub struct SpawnOneRelated<R: Relationship, B: Bundle> {
Expand All @@ -244,54 +232,45 @@ impl<R: Relationship, B: Bundle> DynamicBundle for SpawnOneRelated<R, B> {

fn get_components(
self,
func: &mut impl FnMut(crate::component::StorageType, bevy_ptr::OwningPtr<'_>),
_func: &mut impl FnMut(crate::component::StorageType, bevy_ptr::OwningPtr<'_>),
) -> Self::Effect {
<R::RelationshipTarget as RelationshipTarget>::with_capacity(1).get_components(func);
self
}
}

// SAFETY: This internally relies on the RelationshipTarget's Bundle implementation, which is sound.
// SAFETY: This is a blank implementation.
unsafe impl<R: Relationship, B: Bundle> Bundle for SpawnOneRelated<R, B> {
fn component_ids(
components: &mut crate::component::ComponentsRegistrator,
ids: &mut impl FnMut(crate::component::ComponentId),
_components: &mut crate::component::ComponentsRegistrator,
_ids: &mut impl FnMut(crate::component::ComponentId),
) {
<R::RelationshipTarget as Bundle>::component_ids(components, ids);
}

fn get_component_ids(
components: &crate::component::Components,
ids: &mut impl FnMut(Option<crate::component::ComponentId>),
_components: &crate::component::Components,
_ids: &mut impl FnMut(Option<crate::component::ComponentId>),
) {
<R::RelationshipTarget as Bundle>::get_component_ids(components, ids);
}

fn register_required_components(
components: &mut crate::component::ComponentsRegistrator,
required_components: &mut crate::component::RequiredComponents,
_components: &mut crate::component::ComponentsRegistrator,
_required_components: &mut crate::component::RequiredComponents,
) {
<R::RelationshipTarget as Bundle>::register_required_components(
components,
required_components,
);
}
}

/// [`RelationshipTarget`] methods that create a [`Bundle`] with a [`DynamicBundle::Effect`] that:
///
/// 1. Contains the [`RelationshipTarget`] component, pre-allocated with the necessary space for spawned entities.
/// 2. Spawns an entity (or a list of entities) that relate to the entity the [`Bundle`] is added to via the [`RelationshipTarget::Relationship`].
/// [`RelationshipTarget`] methods that create a [`Bundle`] with a [`DynamicBundle::Effect`] that
/// spawns an entity (or a list of entities) that relate to the entity the [`Bundle`] is added to via the [`RelationshipTarget::Relationship`].
pub trait SpawnRelated: RelationshipTarget {
/// Returns a [`Bundle`] containing this [`RelationshipTarget`] component. It also spawns a [`SpawnableList`] of entities, each related to the bundle's entity
/// via [`RelationshipTarget::Relationship`]. The [`RelationshipTarget`] (when possible) will pre-allocate space for the related entities.
/// Returns a [`Bundle`] that spawns a [`SpawnableList`] of entities, each related to the bundle's entity
/// via [`RelationshipTarget::Relationship`].
///
/// See [`Spawn`], [`SpawnIter`], and [`SpawnWith`] for usage examples.
fn spawn<L: SpawnableList<Self::Relationship>>(
list: L,
) -> SpawnRelatedBundle<Self::Relationship, L>;

/// Returns a [`Bundle`] containing this [`RelationshipTarget`] component. It also spawns a single entity containing [`Bundle`] that is related to the bundle's entity
/// Returns a [`Bundle`] that spawns a single entity containing [`Bundle`] that is related to the bundle's entity
/// via [`RelationshipTarget::Relationship`].
///
/// ```
Expand Down Expand Up @@ -326,8 +305,8 @@ impl<T: RelationshipTarget> SpawnRelated for T {
}
}

/// Returns a [`SpawnRelatedBundle`] that will insert the given [`RelationshipTarget`], spawn a [`SpawnableList`] of entities with given bundles that
/// relate to the [`RelationshipTarget`] entity via the [`RelationshipTarget::Relationship`] component, and reserve space in the [`RelationshipTarget`] for each spawned entity.
/// Returns a [`SpawnRelatedBundle`] that will spawn a [`SpawnableList`] of entities with given bundles that
/// relate to the [`RelationshipTarget`] entity via the [`RelationshipTarget::Relationship`] component.
///
/// The first argument is the [`RelationshipTarget`] type. Any additional arguments will be interpreted as bundles to be spawned.
///
Expand Down