Skip to content

[Merged by Bors] - Fix spawning empty bundles #6425

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

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 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
27 changes: 27 additions & 0 deletions crates/bevy_ecs/src/archetype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ impl ArchetypeId {
}
}

#[derive(Copy, Clone)]
pub(crate) enum ComponentStatus {
Added,
Mutated,
Expand All @@ -45,6 +46,32 @@ pub struct AddBundle {
pub(crate) bundle_status: Vec<ComponentStatus>,
}

pub(crate) trait BundleComponentStatus {
/// Returns the Bundle's component status for the given "bundle index"
///
/// # Safety
/// Callers must ensure that index is always a valid bundle index for the
/// Bundle associated with this [`BundleComponentStatus`]
unsafe fn get_status(&self, index: usize) -> ComponentStatus;
}

impl BundleComponentStatus for AddBundle {
#[inline]
unsafe fn get_status(&self, index: usize) -> ComponentStatus {
// SAFETY: caller has ensured index is a valid bundle index for this bundle
*self.bundle_status.get_unchecked(index)
}
}

pub(crate) struct SpawnBundleStatus;

impl BundleComponentStatus for SpawnBundleStatus {
#[inline]
unsafe fn get_status(&self, _index: usize) -> ComponentStatus {
ComponentStatus::Added
}
}

/// Archetypes and bundles form a graph. Adding or removing a bundle moves
/// an [`Entity`] to a new [`Archetype`].
///
Expand Down
20 changes: 10 additions & 10 deletions crates/bevy_ecs/src/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
pub use bevy_ecs_macros::Bundle;

use crate::{
archetype::{AddBundle, Archetype, ArchetypeId, Archetypes, ComponentStatus},
archetype::{
Archetype, ArchetypeId, Archetypes, BundleComponentStatus, ComponentStatus,
SpawnBundleStatus,
},
component::{Component, ComponentId, ComponentTicks, Components, StorageType},
entity::{Entities, Entity, EntityLocation},
storage::{SparseSetIndex, SparseSets, Storages, Table},
Expand Down Expand Up @@ -340,13 +343,10 @@ impl BundleInfo {
) -> BundleSpawner<'a, 'b> {
let new_archetype_id =
self.add_bundle_to_archetype(archetypes, storages, components, ArchetypeId::EMPTY);
let (empty_archetype, archetype) =
archetypes.get_2_mut(ArchetypeId::EMPTY, new_archetype_id);
let archetype = &mut archetypes[new_archetype_id];
let table = &mut storages.tables[archetype.table_id()];
let add_bundle = empty_archetype.edges().get_add_bundle(self.id()).unwrap();
BundleSpawner {
archetype,
add_bundle,
bundle_info: self,
table,
entities,
Expand All @@ -360,11 +360,11 @@ impl BundleInfo {
/// `entity`, `bundle` must match this [`BundleInfo`]'s type
#[inline]
#[allow(clippy::too_many_arguments)]
unsafe fn write_components<T: Bundle>(
unsafe fn write_components<T: Bundle, S: BundleComponentStatus>(
&self,
table: &mut Table,
sparse_sets: &mut SparseSets,
add_bundle: &AddBundle,
bundle_component_status: &S,
entity: Entity,
table_row: usize,
change_tick: u32,
Expand All @@ -378,7 +378,8 @@ impl BundleInfo {
match self.storage_types[bundle_component] {
StorageType::Table => {
let column = table.get_column_mut(component_id).unwrap();
match add_bundle.bundle_status.get_unchecked(bundle_component) {
// SAFETY: bundle_component is a valid index for this bundle
match bundle_component_status.get_status(bundle_component) {
ComponentStatus::Added => {
column.initialize(
table_row,
Expand Down Expand Up @@ -624,7 +625,6 @@ impl<'a, 'b> BundleInserter<'a, 'b> {
pub(crate) struct BundleSpawner<'a, 'b> {
pub(crate) archetype: &'a mut Archetype,
pub(crate) entities: &'a mut Entities,
add_bundle: &'a AddBundle,
bundle_info: &'b BundleInfo,
table: &'a mut Table,
sparse_sets: &'a mut SparseSets,
Expand All @@ -649,7 +649,7 @@ impl<'a, 'b> BundleSpawner<'a, 'b> {
self.bundle_info.write_components(
self.table,
self.sparse_sets,
self.add_bundle,
&SpawnBundleStatus,
entity,
table_row,
self.change_tick,
Expand Down
7 changes: 7 additions & 0 deletions crates/bevy_ecs/src/world/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1594,6 +1594,7 @@ mod tests {
use crate::{
change_detection::DetectChanges,
component::{ComponentDescriptor, ComponentInfo, StorageType},
prelude::Bundle,
ptr::OwningPtr,
system::Resource,
};
Expand Down Expand Up @@ -1940,4 +1941,10 @@ mod tests {

assert_eq!(entity_counters.len(), 0);
}

#[test]
fn spawn_empty_bundle() {
let mut world = World::new();
world.spawn(());
}
}