diff --git a/crates/bevy_ecs/src/bundle.rs b/crates/bevy_ecs/src/bundle.rs index 999dc63d29..074a750b43 100644 --- a/crates/bevy_ecs/src/bundle.rs +++ b/crates/bevy_ecs/src/bundle.rs @@ -14,7 +14,7 @@ use crate::{ Component, ComponentId, Components, ComponentsRegistrator, RequiredComponentConstructor, RequiredComponents, StorageType, Tick, }, - entity::{Entities, Entity, EntityLocation}, + entity::{Entities, EntitiesAllocator, Entity, EntityLocation}, observer::Observers, prelude::World, query::DebugCheckedUnwrap, @@ -1782,6 +1782,12 @@ impl<'w> BundleSpawner<'w> { (location, after_effect) } + #[inline] + pub fn allocator(&self) -> &'w EntitiesAllocator { + // SAFETY: No outstanding references to self.world, changes to allocator cannot invalidate our internal pointers + unsafe { &self.world.world().allocator } + } + /// # Safety /// `T` must match this [`BundleInfo`]'s type #[inline] @@ -1790,8 +1796,7 @@ impl<'w> BundleSpawner<'w> { bundle: T, caller: MaybeLocation, ) -> (Entity, T::Effect) { - // SAFETY: No outstanding references to self.world, changes to entities cannot invalidate our internal pointers - let entity = unsafe { self.world.world().allocator.alloc() }; + let entity = self.allocator().alloc(); // SAFETY: entity is allocated (but non-existent), `T` matches this BundleInfo's type let (_, after_effect) = unsafe { self.construct(entity, bundle, caller) }; (entity, after_effect) diff --git a/crates/bevy_ecs/src/world/spawn_batch.rs b/crates/bevy_ecs/src/world/spawn_batch.rs index b24eb483a0..58d60a011d 100644 --- a/crates/bevy_ecs/src/world/spawn_batch.rs +++ b/crates/bevy_ecs/src/world/spawn_batch.rs @@ -1,7 +1,7 @@ use crate::{ bundle::{Bundle, BundleSpawner, NoBundleEffect}, change_detection::MaybeLocation, - entity::{Entity, EntitySetIterator}, + entity::{AllocEntitiesIterator, Entity, EntitySetIterator}, world::World, }; use core::iter::FusedIterator; @@ -17,6 +17,7 @@ where { inner: I, spawner: BundleSpawner<'w>, + allocator: AllocEntitiesIterator<'w>, caller: MaybeLocation, } @@ -42,6 +43,7 @@ where Self { inner: iter, + allocator: spawner.allocator().alloc_many(length as u32), spawner, caller, } @@ -71,8 +73,16 @@ where fn next(&mut self) -> Option { let bundle = self.inner.next()?; - // SAFETY: bundle matches spawner type - unsafe { Some(self.spawner.spawn(bundle, self.caller).0) } + Some(if let Some(bulk) = self.allocator.next() { + // SAFETY: bundle matches spawner type and we just allocated it + unsafe { + self.spawner.construct(bulk, bundle, self.caller); + } + bulk + } else { + // SAFETY: bundle matches spawner type + unsafe { self.spawner.spawn(bundle, self.caller).0 } + }) } fn size_hint(&self) -> (usize, Option) {