diff --git a/benches/benches/bevy_ecs/world/commands.rs b/benches/benches/bevy_ecs/world/commands.rs index 6ff63b2e20..8ad87862eb 100644 --- a/benches/benches/bevy_ecs/world/commands.rs +++ b/benches/benches/bevy_ecs/world/commands.rs @@ -106,6 +106,10 @@ pub fn insert_commands(criterion: &mut Criterion) { for entity in &entities { values.push((*entity, (Matrix::default(), Vec3::default()))); } + #[expect( + deprecated, + reason = "This needs to be supported for now, and therefore still needs the benchmark." + )] commands.insert_or_spawn_batch(values); command_queue.apply(&mut world); }); diff --git a/crates/bevy_ecs/src/entity/mod.rs b/crates/bevy_ecs/src/entity/mod.rs index 5f701525d6..3d5aa6d566 100644 --- a/crates/bevy_ecs/src/entity/mod.rs +++ b/crates/bevy_ecs/src/entity/mod.rs @@ -246,6 +246,9 @@ impl Hash for Entity { } } +#[deprecated( + note = "This is exclusively used with the now deprecated `Entities::alloc_at_without_replacement`." +)] pub(crate) enum AllocAtWithoutReplacement { Exists(EntityLocation), DidNotExist, @@ -697,6 +700,9 @@ impl Entities { /// /// Returns the location of the entity currently using the given ID, if any. Location should be /// written immediately. + #[deprecated( + note = "This can cause extreme performance problems when used after freeing a large number of entities and requesting an arbitrary entity. See #18054 on GitHub." + )] pub fn alloc_at(&mut self, entity: Entity) -> Option { self.verify_flushed(); @@ -730,6 +736,13 @@ impl Entities { /// Allocate a specific entity ID, overwriting its generation. /// /// Returns the location of the entity currently using the given ID, if any. + #[deprecated( + note = "This can cause extreme performance problems when used after freeing a large number of entities and requesting an arbitrary entity. See #18054 on GitHub." + )] + #[expect( + deprecated, + reason = "We need to support `AllocAtWithoutReplacement` for now." + )] pub(crate) fn alloc_at_without_replacement( &mut self, entity: Entity, diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index bae3dbfed2..3b1229ab2a 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -1702,6 +1702,10 @@ mod tests { let values = vec![(e0, (B(0), C)), (e1, (B(1), C))]; + #[expect( + deprecated, + reason = "This needs to be supported for now, and therefore still needs the test." + )] world.insert_or_spawn_batch(values).unwrap(); assert_eq!( @@ -1742,6 +1746,10 @@ mod tests { let values = vec![(e0, (B(0), C)), (e1, (B(1), C)), (invalid_e2, (B(2), C))]; + #[expect( + deprecated, + reason = "This needs to be supported for now, and therefore still needs the test." + )] let result = world.insert_or_spawn_batch(values); assert_eq!( diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index 12c5427225..d569b7ca7b 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -681,6 +681,9 @@ impl<'w, 's> Commands<'w, 's> { /// This method should generally only be used for sharing entities across apps, and only when they have a scheme /// worked out to share an ID space (which doesn't happen by default). #[track_caller] + #[deprecated( + note = "This can cause extreme performance problems when used with lots of arbitrary free entities. See #18054 on GitHub." + )] pub fn insert_or_spawn_batch(&mut self, bundles_iter: I) where I: IntoIterator + Send + Sync + 'static, @@ -688,6 +691,11 @@ impl<'w, 's> Commands<'w, 's> { { let caller = MaybeLocation::caller(); self.queue(move |world: &mut World| { + + #[expect( + deprecated, + reason = "This needs to be supported for now, and the outer item is deprecated too." + )] if let Err(invalid_entities) = world.insert_or_spawn_batch_with_caller( bundles_iter, caller, diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 10db34bac3..e61abd7920 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -30,6 +30,10 @@ pub use filtered_resource::*; pub use identifier::WorldId; pub use spawn_batch::*; +#[expect( + deprecated, + reason = "We need to support `AllocAtWithoutReplacement` for now." +)] use crate::{ archetype::{ArchetypeId, ArchetypeRow, Archetypes}, bundle::{ @@ -2154,18 +2158,28 @@ impl World { /// assert_eq!(world.get::(e0), Some(&B(0.0))); /// ``` #[track_caller] + #[deprecated( + note = "This can cause extreme performance problems when used with lots of arbitrary free entities. See #18054 on GitHub." + )] pub fn insert_or_spawn_batch(&mut self, iter: I) -> Result<(), Vec> where I: IntoIterator, I::IntoIter: Iterator, B: Bundle, { + #[expect( + deprecated, + reason = "This needs to be supported for now, and the outer function is deprecated too." + )] self.insert_or_spawn_batch_with_caller(iter, MaybeLocation::caller()) } /// Split into a new function so we can pass the calling location into the function when using /// as a command. #[inline] + #[deprecated( + note = "This can cause extreme performance problems when used with lots of arbitrary free entities. See #18054 on GitHub." + )] pub(crate) fn insert_or_spawn_batch_with_caller( &mut self, iter: I, @@ -2203,6 +2217,10 @@ impl World { let mut invalid_entities = Vec::new(); for (entity, bundle) in iter { + #[expect( + deprecated, + reason = "This needs to be supported for now, and the outer function is deprecated too." + )] match spawn_or_insert .entities() .alloc_at_without_replacement(entity)