diff --git a/crates/bevy_ecs/src/archetype.rs b/crates/bevy_ecs/src/archetype.rs index a64023489674c..7fb308dadae7f 100644 --- a/crates/bevy_ecs/src/archetype.rs +++ b/crates/bevy_ecs/src/archetype.rs @@ -158,12 +158,12 @@ pub struct Edges { impl Edges { /// Checks the cache for the target archetype when adding a bundle to the - /// source archetype. For more information, see [`EntityMut::insert`]. + /// source archetype. For more information, see [`EntityWorldMut::insert`]. /// /// If this returns `None`, it means there has not been a transition from /// the source archetype via the provided bundle. /// - /// [`EntityMut::insert`]: crate::world::EntityMut::insert + /// [`EntityWorldMut::insert`]: crate::world::EntityWorldMut::insert #[inline] pub fn get_add_bundle(&self, bundle_id: BundleId) -> Option { self.get_add_bundle_internal(bundle_id) @@ -177,9 +177,9 @@ impl Edges { } /// Caches the target archetype when adding a bundle to the source archetype. - /// For more information, see [`EntityMut::insert`]. + /// For more information, see [`EntityWorldMut::insert`]. /// - /// [`EntityMut::insert`]: crate::world::EntityMut::insert + /// [`EntityWorldMut::insert`]: crate::world::EntityWorldMut::insert #[inline] pub(crate) fn insert_add_bundle( &mut self, @@ -197,7 +197,7 @@ impl Edges { } /// Checks the cache for the target archetype when removing a bundle to the - /// source archetype. For more information, see [`EntityMut::remove`]. + /// source archetype. For more information, see [`EntityWorldMut::remove`]. /// /// If this returns `None`, it means there has not been a transition from /// the source archetype via the provided bundle. @@ -205,16 +205,16 @@ impl Edges { /// If this returns `Some(None)`, it means that the bundle cannot be removed /// from the source archetype. /// - /// [`EntityMut::remove`]: crate::world::EntityMut::remove + /// [`EntityWorldMut::remove`]: crate::world::EntityWorldMut::remove #[inline] pub fn get_remove_bundle(&self, bundle_id: BundleId) -> Option> { self.remove_bundle.get(bundle_id).cloned() } /// Caches the target archetype when removing a bundle to the source archetype. - /// For more information, see [`EntityMut::remove`]. + /// For more information, see [`EntityWorldMut::remove`]. /// - /// [`EntityMut::remove`]: crate::world::EntityMut::remove + /// [`EntityWorldMut::remove`]: crate::world::EntityWorldMut::remove #[inline] pub(crate) fn insert_remove_bundle( &mut self, @@ -225,21 +225,21 @@ impl Edges { } /// Checks the cache for the target archetype when removing a bundle to the - /// source archetype. For more information, see [`EntityMut::remove`]. + /// source archetype. For more information, see [`EntityWorldMut::remove`]. /// /// If this returns `None`, it means there has not been a transition from /// the source archetype via the provided bundle. /// - /// [`EntityMut::remove`]: crate::world::EntityMut::remove + /// [`EntityWorldMut::remove`]: crate::world::EntityWorldMut::remove #[inline] pub fn get_take_bundle(&self, bundle_id: BundleId) -> Option> { self.take_bundle.get(bundle_id).cloned() } /// Caches the target archetype when removing a bundle to the source archetype. - /// For more information, see [`EntityMut::take`]. + /// For more information, see [`EntityWorldMut::take`]. /// - /// [`EntityMut::take`]: crate::world::EntityMut::take + /// [`EntityWorldMut::take`]: crate::world::EntityWorldMut::take #[inline] pub(crate) fn insert_take_bundle( &mut self, diff --git a/crates/bevy_ecs/src/entity/mod.rs b/crates/bevy_ecs/src/entity/mod.rs index 99dd7fe791a30..3a49c99aedcf6 100644 --- a/crates/bevy_ecs/src/entity/mod.rs +++ b/crates/bevy_ecs/src/entity/mod.rs @@ -21,8 +21,8 @@ //! |Spawn an entity with components|[`Commands::spawn`]|[`World::spawn`]| //! |Spawn an entity without components|[`Commands::spawn_empty`]|[`World::spawn_empty`]| //! |Despawn an entity|[`EntityCommands::despawn`]|[`World::despawn`]| -//! |Insert a component, bundle, or tuple of components and bundles to an entity|[`EntityCommands::insert`]|[`EntityMut::insert`]| -//! |Remove a component, bundle, or tuple of components and bundles from an entity|[`EntityCommands::remove`]|[`EntityMut::remove`]| +//! |Insert a component, bundle, or tuple of components and bundles to an entity|[`EntityCommands::insert`]|[`EntityWorldMut::insert`]| +//! |Remove a component, bundle, or tuple of components and bundles from an entity|[`EntityCommands::remove`]|[`EntityWorldMut::remove`]| //! //! [`World`]: crate::world::World //! [`Commands::spawn`]: crate::system::Commands::spawn @@ -33,8 +33,8 @@ //! [`World::spawn`]: crate::world::World::spawn //! [`World::spawn_empty`]: crate::world::World::spawn_empty //! [`World::despawn`]: crate::world::World::despawn -//! [`EntityMut::insert`]: crate::world::EntityMut::insert -//! [`EntityMut::remove`]: crate::world::EntityMut::remove +//! [`EntityWorldMut::insert`]: crate::world::EntityWorldMut::insert +//! [`EntityWorldMut::remove`]: crate::world::EntityWorldMut::remove mod map_entities; pub use map_entities::*; @@ -72,7 +72,7 @@ type IdCursor = isize; /// # Usage /// /// This data type is returned by iterating a `Query` that has `Entity` as part of its query fetch type parameter ([learn more]). -/// It can also be obtained by calling [`EntityCommands::id`] or [`EntityMut::id`]. +/// It can also be obtained by calling [`EntityCommands::id`] or [`EntityWorldMut::id`]. /// /// ``` /// # use bevy_ecs::prelude::*; @@ -84,7 +84,7 @@ type IdCursor = isize; /// } /// /// fn exclusive_system(world: &mut World) { -/// // Calling `spawn` returns `EntityMut`. +/// // Calling `spawn` returns `EntityWorldMut`. /// let entity = world.spawn(SomeComponent).id(); /// } /// # @@ -111,7 +111,7 @@ type IdCursor = isize; /// /// [learn more]: crate::system::Query#entity-id-access /// [`EntityCommands::id`]: crate::system::EntityCommands::id -/// [`EntityMut::id`]: crate::world::EntityMut::id +/// [`EntityWorldMut::id`]: crate::world::EntityWorldMut::id /// [`EntityCommands`]: crate::system::EntityCommands /// [`Query::get`]: crate::system::Query::get /// [`World`]: crate::world::World diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index c60356f4da91c..b9b8718094abe 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -52,7 +52,7 @@ pub mod prelude { Commands, Deferred, In, IntoSystem, Local, NonSend, NonSendMut, ParallelCommands, ParamSet, Query, ReadOnlySystem, Res, ResMut, Resource, System, SystemParamFunction, }, - world::{EntityRef, FromWorld, World}, + world::{EntityMut, EntityRef, EntityWorldMut, FromWorld, World}, }; } diff --git a/crates/bevy_ecs/src/query/access.rs b/crates/bevy_ecs/src/query/access.rs index 41a23020ac5f4..808d31d2c48e7 100644 --- a/crates/bevy_ecs/src/query/access.rs +++ b/crates/bevy_ecs/src/query/access.rs @@ -53,9 +53,12 @@ pub struct Access { reads_and_writes: FixedBitSet, /// The exclusively-accessed elements. writes: FixedBitSet, - /// Is `true` if this has access to all elements in the collection? + /// Is `true` if this has access to all elements in the collection. /// This field is a performance optimization for `&World` (also harder to mess up for soundness). reads_all: bool, + /// Is `true` if this has mutable access to all elements in the collection. + /// If this is true, then `reads_all` must also be true. + writes_all: bool, marker: PhantomData, } @@ -68,6 +71,7 @@ impl fmt::Debug for Access { ) .field("writes", &FormattedBitSet::::new(&self.writes)) .field("reads_all", &self.reads_all) + .field("writes_all", &self.writes_all) .finish() } } @@ -83,6 +87,7 @@ impl Access { pub const fn new() -> Self { Self { reads_all: false, + writes_all: false, reads_and_writes: FixedBitSet::new(), writes: FixedBitSet::new(), marker: PhantomData, @@ -116,14 +121,19 @@ impl Access { self.reads_all || self.reads_and_writes.contains(index.sparse_set_index()) } + /// Returns `true` if this can access anything. + pub fn has_any_read(&self) -> bool { + self.reads_all || !self.reads_and_writes.is_clear() + } + /// Returns `true` if this can exclusively access the element given by `index`. pub fn has_write(&self, index: T) -> bool { - self.writes.contains(index.sparse_set_index()) + self.writes_all || self.writes.contains(index.sparse_set_index()) } /// Returns `true` if this accesses anything mutably. pub fn has_any_write(&self) -> bool { - !self.writes.is_clear() + self.writes_all || !self.writes.is_clear() } /// Sets this as having access to all indexed elements (i.e. `&World`). @@ -131,14 +141,26 @@ impl Access { self.reads_all = true; } + /// Sets this as having mutable access to all indexed elements (i.e. `EntityMut`). + pub fn write_all(&mut self) { + self.reads_all = true; + self.writes_all = true; + } + /// Returns `true` if this has access to all indexed elements (i.e. `&World`). pub fn has_read_all(&self) -> bool { self.reads_all } + /// Returns `true` if this has write access to all indexed elements (i.e. `EntityMut`). + pub fn has_write_all(&self) -> bool { + self.writes_all + } + /// Removes all accesses. pub fn clear(&mut self) { self.reads_all = false; + self.writes_all = false; self.reads_and_writes.clear(); self.writes.clear(); } @@ -146,6 +168,7 @@ impl Access { /// Adds all access from `other`. pub fn extend(&mut self, other: &Access) { self.reads_all = self.reads_all || other.reads_all; + self.writes_all = self.writes_all || other.writes_all; self.reads_and_writes.union_with(&other.reads_and_writes); self.writes.union_with(&other.writes); } @@ -155,13 +178,20 @@ impl Access { /// [`Access`] instances are incompatible if one can write /// an element that the other can read or write. pub fn is_compatible(&self, other: &Access) -> bool { - // Only systems that do not write data are compatible with systems that operate on `&World`. + if self.writes_all { + return !other.has_any_read(); + } + + if other.writes_all { + return !self.has_any_read(); + } + if self.reads_all { - return other.writes.count_ones(..) == 0; + return !other.has_any_write(); } if other.reads_all { - return self.writes.count_ones(..) == 0; + return !self.has_any_write(); } self.writes.is_disjoint(&other.reads_and_writes) @@ -172,12 +202,23 @@ impl Access { pub fn get_conflicts(&self, other: &Access) -> Vec { let mut conflicts = FixedBitSet::default(); if self.reads_all { + // QUESTION: How to handle `other.writes_all`? conflicts.extend(other.writes.ones()); } if other.reads_all { + // QUESTION: How to handle `self.writes_all`. conflicts.extend(self.writes.ones()); } + + if self.writes_all { + conflicts.extend(other.reads_and_writes.ones()); + } + + if other.writes_all { + conflicts.extend(self.reads_and_writes.ones()); + } + conflicts.extend(self.writes.intersection(&other.reads_and_writes)); conflicts.extend(self.reads_and_writes.intersection(&other.writes)); conflicts @@ -377,6 +418,11 @@ impl FilteredAccess { pub fn read_all(&mut self) { self.access.read_all(); } + + /// Sets the underlying unfiltered access as having mutable access to all indexed elements. + pub fn write_all(&mut self) { + self.access.write_all(); + } } #[derive(Clone, Eq, PartialEq)] diff --git a/crates/bevy_ecs/src/query/fetch.rs b/crates/bevy_ecs/src/query/fetch.rs index 240124632248d..c477e01597e86 100644 --- a/crates/bevy_ecs/src/query/fetch.rs +++ b/crates/bevy_ecs/src/query/fetch.rs @@ -5,7 +5,7 @@ use crate::{ entity::Entity, query::{Access, DebugCheckedUnwrap, FilteredAccess}, storage::{ComponentSparseSet, Table, TableRow}, - world::{unsafe_world_cell::UnsafeWorldCell, EntityRef, Mut, Ref, World}, + world::{unsafe_world_cell::UnsafeWorldCell, EntityMut, EntityRef, Mut, Ref, World}, }; pub use bevy_ecs_macros::WorldQuery; use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref}; @@ -524,8 +524,8 @@ unsafe impl WorldQuery for Entity { unsafe impl ReadOnlyWorldQuery for Entity {} /// SAFETY: `Self` is the same as `Self::ReadOnly` -unsafe impl<'a> WorldQuery for EntityRef<'a> { - type Fetch<'w> = &'w World; +unsafe impl WorldQuery for EntityRef<'_> { + type Fetch<'w> = UnsafeWorldCell<'w>; type Item<'w> = EntityRef<'w>; type ReadOnly = Self; type State = (); @@ -544,8 +544,7 @@ unsafe impl<'a> WorldQuery for EntityRef<'a> { _last_run: Tick, _this_run: Tick, ) -> Self::Fetch<'w> { - // SAFE: EntityRef has permission to access the whole world immutably thanks to update_component_access and update_archetype_component_access - world.world() + world } #[inline] @@ -568,7 +567,9 @@ unsafe impl<'a> WorldQuery for EntityRef<'a> { _table_row: TableRow, ) -> Self::Item<'w> { // SAFETY: `fetch` must be called with an entity that exists in the world - unsafe { world.get_entity(entity).debug_checked_unwrap() } + let cell = world.get_entity(entity).debug_checked_unwrap(); + // SAFETY: Read-only access to every component has been registered. + EntityRef::new(cell) } fn update_component_access(_state: &Self::State, access: &mut FilteredAccess) { @@ -599,8 +600,85 @@ unsafe impl<'a> WorldQuery for EntityRef<'a> { } } -/// SAFETY: access is read only -unsafe impl<'a> ReadOnlyWorldQuery for EntityRef<'a> {} +/// SAFETY: Access is read-only. +unsafe impl ReadOnlyWorldQuery for EntityRef<'_> {} + +/// SAFETY: The accesses of `Self::ReadOnly` are a subset of the accesses of `Self` +unsafe impl<'a> WorldQuery for EntityMut<'a> { + type Fetch<'w> = UnsafeWorldCell<'w>; + type Item<'w> = EntityMut<'w>; + type ReadOnly = EntityRef<'a>; + type State = (); + + fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> { + item + } + + const IS_DENSE: bool = true; + + const IS_ARCHETYPAL: bool = true; + + unsafe fn init_fetch<'w>( + world: UnsafeWorldCell<'w>, + _state: &Self::State, + _last_run: Tick, + _this_run: Tick, + ) -> Self::Fetch<'w> { + world + } + + #[inline] + unsafe fn set_archetype<'w>( + _fetch: &mut Self::Fetch<'w>, + _state: &Self::State, + _archetype: &'w Archetype, + _table: &Table, + ) { + } + + #[inline] + unsafe fn set_table<'w>(_fetch: &mut Self::Fetch<'w>, _state: &Self::State, _table: &'w Table) { + } + + #[inline(always)] + unsafe fn fetch<'w>( + world: &mut Self::Fetch<'w>, + entity: Entity, + _table_row: TableRow, + ) -> Self::Item<'w> { + // SAFETY: `fetch` must be called with an entity that exists in the world + let cell = world.get_entity(entity).debug_checked_unwrap(); + // SAFETY: mutable access to every component has been registered. + EntityMut::new(cell) + } + + fn update_component_access(_state: &Self::State, access: &mut FilteredAccess) { + assert!( + !access.access().has_any_read(), + "EntityMut conflicts with a previous access in this query. Exclusive access cannot coincide with any other accesses.", + ); + access.write_all(); + } + + fn update_archetype_component_access( + _state: &Self::State, + archetype: &Archetype, + access: &mut Access, + ) { + for component_id in archetype.components() { + access.add_write(archetype.get_archetype_component_id(component_id).unwrap()); + } + } + + fn init_state(_world: &mut World) {} + + fn matches_component_set( + _state: &Self::State, + _set_contains_id: &impl Fn(ComponentId) -> bool, + ) -> bool { + true + } +} #[doc(hidden)] pub struct ReadFetch<'w, T> { diff --git a/crates/bevy_ecs/src/reflect/bundle.rs b/crates/bevy_ecs/src/reflect/bundle.rs index 7fc07d855e6b3..8b5f5e20843c8 100644 --- a/crates/bevy_ecs/src/reflect/bundle.rs +++ b/crates/bevy_ecs/src/reflect/bundle.rs @@ -7,7 +7,7 @@ use std::any::TypeId; use crate::{ prelude::Bundle, - world::{EntityMut, FromWorld, World}, + world::{EntityWorldMut, FromWorld, World}, }; use bevy_reflect::{FromType, Reflect, ReflectRef, TypeRegistry}; @@ -28,13 +28,13 @@ pub struct ReflectBundleFns { /// Function pointer implementing [`ReflectBundle::from_world()`]. pub from_world: fn(&mut World) -> Box, /// Function pointer implementing [`ReflectBundle::insert()`]. - pub insert: fn(&mut EntityMut, &dyn Reflect), + pub insert: fn(&mut EntityWorldMut, &dyn Reflect), /// Function pointer implementing [`ReflectBundle::apply()`]. - pub apply: fn(&mut EntityMut, &dyn Reflect, &TypeRegistry), + pub apply: fn(&mut EntityWorldMut, &dyn Reflect, &TypeRegistry), /// Function pointer implementing [`ReflectBundle::apply_or_insert()`]. - pub apply_or_insert: fn(&mut EntityMut, &dyn Reflect, &TypeRegistry), + pub apply_or_insert: fn(&mut EntityWorldMut, &dyn Reflect, &TypeRegistry), /// Function pointer implementing [`ReflectBundle::remove()`]. - pub remove: fn(&mut EntityMut), + pub remove: fn(&mut EntityWorldMut), } impl ReflectBundleFns { @@ -54,8 +54,8 @@ impl ReflectBundle { (self.0.from_world)(world) } - /// Insert a reflected [`Bundle`] into the entity like [`insert()`](crate::world::EntityMut::insert). - pub fn insert(&self, entity: &mut EntityMut, bundle: &dyn Reflect) { + /// Insert a reflected [`Bundle`] into the entity like [`insert()`](crate::world::EntityWorldMut::insert). + pub fn insert(&self, entity: &mut EntityWorldMut, bundle: &dyn Reflect) { (self.0.insert)(entity, bundle); } @@ -64,14 +64,19 @@ impl ReflectBundle { /// # Panics /// /// Panics if there is no [`Bundle`] of the given type. - pub fn apply(&self, entity: &mut EntityMut, bundle: &dyn Reflect, registry: &TypeRegistry) { + pub fn apply( + &self, + entity: &mut EntityWorldMut, + bundle: &dyn Reflect, + registry: &TypeRegistry, + ) { (self.0.apply)(entity, bundle, registry); } /// Uses reflection to set the value of this [`Bundle`] type in the entity to the given value or insert a new one if it does not exist. pub fn apply_or_insert( &self, - entity: &mut EntityMut, + entity: &mut EntityWorldMut, bundle: &dyn Reflect, registry: &TypeRegistry, ) { @@ -79,7 +84,7 @@ impl ReflectBundle { } /// Removes this [`Bundle`] type from the entity. Does nothing if it doesn't exist. - pub fn remove(&self, entity: &mut EntityMut) { + pub fn remove(&self, entity: &mut EntityWorldMut) { (self.0.remove)(entity); } @@ -169,7 +174,11 @@ impl FromType for ReflectBundle { } } -fn insert_field(entity: &mut EntityMut, field: &dyn Reflect, registry: &TypeRegistry) { +fn insert_field( + entity: &mut EntityWorldMut, + field: &dyn Reflect, + registry: &TypeRegistry, +) { if let Some(reflect_component) = registry.get_type_data::(field.type_id()) { reflect_component.apply(entity, field); } else if let Some(reflect_bundle) = registry.get_type_data::(field.type_id()) { @@ -192,7 +201,7 @@ fn insert_field(entity: &mut EntityMut, field: &dyn Reflect, registr } fn apply_or_insert_field( - entity: &mut EntityMut, + entity: &mut EntityWorldMut, field: &dyn Reflect, registry: &TypeRegistry, ) { diff --git a/crates/bevy_ecs/src/reflect/component.rs b/crates/bevy_ecs/src/reflect/component.rs index 94b36d0953fbf..f91ac8e900225 100644 --- a/crates/bevy_ecs/src/reflect/component.rs +++ b/crates/bevy_ecs/src/reflect/component.rs @@ -25,7 +25,7 @@ //! implementation of `ReflectComponent`. //! //! The `FromType` impl creates a function per field of [`ReflectComponentFns`]. -//! In those functions, we call generic methods on [`World`] and [`EntityMut`]. +//! In those functions, we call generic methods on [`World`] and [`EntityWorldMut`]. //! //! The result is a `ReflectComponent` completely independent of `C`, yet capable //! of using generic ECS methods such as `entity.get::()` to get `&dyn Reflect` @@ -50,7 +50,7 @@ use crate::{ change_detection::Mut, component::Component, entity::Entity, - world::{unsafe_world_cell::UnsafeEntityCell, EntityMut, EntityRef, FromWorld, World}, + world::{unsafe_world_cell::UnsafeEntityCell, EntityRef, EntityWorldMut, FromWorld, World}, }; use bevy_reflect::{FromType, Reflect}; @@ -86,19 +86,19 @@ pub struct ReflectComponentFns { /// Function pointer implementing [`ReflectComponent::from_world()`]. pub from_world: fn(&mut World) -> Box, /// Function pointer implementing [`ReflectComponent::insert()`]. - pub insert: fn(&mut EntityMut, &dyn Reflect), + pub insert: fn(&mut EntityWorldMut, &dyn Reflect), /// Function pointer implementing [`ReflectComponent::apply()`]. - pub apply: fn(&mut EntityMut, &dyn Reflect), + pub apply: fn(&mut EntityWorldMut, &dyn Reflect), /// Function pointer implementing [`ReflectComponent::apply_or_insert()`]. - pub apply_or_insert: fn(&mut EntityMut, &dyn Reflect), + pub apply_or_insert: fn(&mut EntityWorldMut, &dyn Reflect), /// Function pointer implementing [`ReflectComponent::remove()`]. - pub remove: fn(&mut EntityMut), + pub remove: fn(&mut EntityWorldMut), /// Function pointer implementing [`ReflectComponent::contains()`]. pub contains: fn(EntityRef) -> bool, /// Function pointer implementing [`ReflectComponent::reflect()`]. pub reflect: fn(EntityRef) -> Option<&dyn Reflect>, /// Function pointer implementing [`ReflectComponent::reflect_mut()`]. - pub reflect_mut: for<'a> fn(&'a mut EntityMut<'_>) -> Option>, + pub reflect_mut: for<'a> fn(&'a mut EntityWorldMut<'_>) -> Option>, /// Function pointer implementing [`ReflectComponent::reflect_unchecked_mut()`]. /// /// # Safety @@ -125,8 +125,8 @@ impl ReflectComponent { (self.0.from_world)(world) } - /// Insert a reflected [`Component`] into the entity like [`insert()`](crate::world::EntityMut::insert). - pub fn insert(&self, entity: &mut EntityMut, component: &dyn Reflect) { + /// Insert a reflected [`Component`] into the entity like [`insert()`](crate::world::EntityWorldMut::insert). + pub fn insert(&self, entity: &mut EntityWorldMut, component: &dyn Reflect) { (self.0.insert)(entity, component); } @@ -135,17 +135,17 @@ impl ReflectComponent { /// # Panics /// /// Panics if there is no [`Component`] of the given type. - pub fn apply(&self, entity: &mut EntityMut, component: &dyn Reflect) { + pub fn apply(&self, entity: &mut EntityWorldMut, component: &dyn Reflect) { (self.0.apply)(entity, component); } /// Uses reflection to set the value of this [`Component`] type in the entity to the given value or insert a new one if it does not exist. - pub fn apply_or_insert(&self, entity: &mut EntityMut, component: &dyn Reflect) { + pub fn apply_or_insert(&self, entity: &mut EntityWorldMut, component: &dyn Reflect) { (self.0.apply_or_insert)(entity, component); } /// Removes this [`Component`] type from the entity. Does nothing if it doesn't exist. - pub fn remove(&self, entity: &mut EntityMut) { + pub fn remove(&self, entity: &mut EntityWorldMut) { (self.0.remove)(entity); } @@ -160,7 +160,10 @@ impl ReflectComponent { } /// Gets the value of this [`Component`] type from the entity as a mutable reflected reference. - pub fn reflect_mut<'a>(&self, entity: &'a mut EntityMut<'_>) -> Option> { + pub fn reflect_mut<'a>( + &self, + entity: &'a mut EntityWorldMut<'_>, + ) -> Option> { (self.0.reflect_mut)(entity) } diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index 3c404a551c97e..2d25ab36a3666 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -5,7 +5,7 @@ use crate::{ self as bevy_ecs, bundle::Bundle, entity::{Entities, Entity}, - world::{EntityMut, FromWorld, World}, + world::{EntityWorldMut, FromWorld, World}, }; use bevy_ecs_macros::SystemParam; use bevy_utils::tracing::{error, info}; @@ -724,7 +724,7 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> { /// Removes a [`Bundle`] of components from the entity. /// - /// See [`EntityMut::remove`](crate::world::EntityMut::remove) for more + /// See [`EntityWorldMut::remove`](crate::world::EntityWorldMut::remove) for more /// details. /// /// # Example @@ -805,12 +805,11 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> { /// /// ``` /// # use bevy_ecs::prelude::*; - /// # use bevy_ecs::world::EntityMut; /// # fn my_system(mut commands: Commands) { /// commands /// .spawn_empty() /// // Closures with this signature implement `EntityCommand`. - /// .add(|entity: EntityMut| { + /// .add(|entity: EntityWorldMut| { /// println!("Executed an EntityCommand for {:?}", entity.id()); /// }); /// # } @@ -849,7 +848,7 @@ where impl EntityCommand for F where - F: FnOnce(EntityMut) + Send + 'static, + F: FnOnce(EntityWorldMut) + Send + 'static, { fn apply(self, id: Entity, world: &mut World) { self(world.entity_mut(id)); diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index 29a63c2220d60..52534604990a7 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -14,64 +14,54 @@ use std::any::TypeId; use super::{unsafe_world_cell::UnsafeEntityCell, Ref}; -/// A read-only reference to a particular [`Entity`] and all of its components +/// A read-only reference to a particular [`Entity`] and all of its components. +/// +/// # Examples +/// +/// Read-only access disjoint with mutable access. +/// +/// ``` +/// # use bevy_ecs::prelude::*; +/// # #[derive(Component)] pub struct A; +/// # #[derive(Component)] pub struct B; +/// fn disjoint_system( +/// query1: Query<&mut A>, +/// query2: Query>, +/// ) { +/// // ... +/// } +/// # bevy_ecs::system::assert_is_system(disjoint_system); +/// ``` #[derive(Copy, Clone)] -pub struct EntityRef<'w> { - world: &'w World, - entity: Entity, - location: EntityLocation, -} +pub struct EntityRef<'w>(UnsafeEntityCell<'w>); impl<'w> EntityRef<'w> { /// # Safety - /// - /// - `entity` must be valid for `world`: the generation should match that of the entity at the same index. - /// - `location` must be sourced from `world`'s `Entities` and must exactly match the location for `entity` - /// - /// The above is trivially satisfied if `location` was sourced from `world.entities().get(entity)`. + /// - `cell` must have permission to read every component of the entity. + /// - No mutable accesses to any of the entity's components may exist + /// at the same time as the returned [`EntityRef`]. #[inline] - pub(crate) unsafe fn new(world: &'w World, entity: Entity, location: EntityLocation) -> Self { - debug_assert!(world.entities().contains(entity)); - debug_assert_eq!(world.entities().get(entity), Some(location)); - - Self { - world, - entity, - location, - } - } - - fn as_unsafe_world_cell_readonly(&self) -> UnsafeEntityCell<'w> { - UnsafeEntityCell::new( - self.world.as_unsafe_world_cell_readonly(), - self.entity, - self.location, - ) + pub(crate) unsafe fn new(cell: UnsafeEntityCell<'w>) -> Self { + Self(cell) } /// Returns the [ID](Entity) of the current entity. #[inline] #[must_use = "Omit the .id() call if you do not need to store the `Entity` identifier."] pub fn id(&self) -> Entity { - self.entity + self.0.id() } /// Gets metadata indicating the location where the current entity is stored. #[inline] pub fn location(&self) -> EntityLocation { - self.location + self.0.location() } /// Returns the archetype that the current entity belongs to. #[inline] pub fn archetype(&self) -> &Archetype { - &self.world.archetypes[self.location.archetype_id] - } - - /// Gets read-only access to the world that the current entity belongs to. - #[inline] - pub fn world(&self) -> &'w World { - self.world + self.0.archetype() } /// Returns `true` if the current entity has a component of type `T`. @@ -96,8 +86,7 @@ impl<'w> EntityRef<'w> { /// [`Self::contains_type_id`]. #[inline] pub fn contains_id(&self, component_id: ComponentId) -> bool { - self.as_unsafe_world_cell_readonly() - .contains_id(component_id) + self.0.contains_id(component_id) } /// Returns `true` if the current entity has a component with the type identified by `type_id`. @@ -109,16 +98,15 @@ impl<'w> EntityRef<'w> { /// - If you have a [`ComponentId`] instead of a [`TypeId`], consider using [`Self::contains_id`]. #[inline] pub fn contains_type_id(&self, type_id: TypeId) -> bool { - self.as_unsafe_world_cell_readonly() - .contains_type_id(type_id) + self.0.contains_type_id(type_id) } /// Gets access to the component of type `T` for the current entity. /// Returns `None` if the entity does not have a component of type `T`. #[inline] pub fn get(&self) -> Option<&'w T> { - // SAFETY: &self implies shared access for duration of returned value - unsafe { self.as_unsafe_world_cell_readonly().get::() } + // SAFETY: We have read-only access to all components of this entity. + unsafe { self.0.get::() } } /// Gets access to the component of type `T` for the current entity, @@ -127,16 +115,16 @@ impl<'w> EntityRef<'w> { /// Returns `None` if the entity does not have a component of type `T`. #[inline] pub fn get_ref(&self) -> Option> { - // SAFETY: &self implies shared access for duration of returned value - unsafe { self.as_unsafe_world_cell_readonly().get_ref::() } + // SAFETY: We have read-only access to all components of this entity. + unsafe { self.0.get_ref::() } } /// Retrieves the change ticks for the given component. This can be useful for implementing change /// detection in custom runtimes. #[inline] pub fn get_change_ticks(&self) -> Option { - // SAFETY: &self implies shared access - unsafe { self.as_unsafe_world_cell_readonly().get_change_ticks::() } + // SAFETY: We have read-only access to all components of this entity. + unsafe { self.0.get_change_ticks::() } } /// Retrieves the change ticks for the given [`ComponentId`]. This can be useful for implementing change @@ -147,15 +135,10 @@ impl<'w> EntityRef<'w> { /// compile time.** #[inline] pub fn get_change_ticks_by_id(&self, component_id: ComponentId) -> Option { - // SAFETY: &self implies shared access - unsafe { - self.as_unsafe_world_cell_readonly() - .get_change_ticks_by_id(component_id) - } + // SAFETY: We have read-only access to all components of this entity. + unsafe { self.0.get_change_ticks_by_id(component_id) } } -} -impl<'w> EntityRef<'w> { /// Gets the component of the given [`ComponentId`] from the entity. /// /// **You should prefer to use the typed API where possible and only @@ -166,35 +149,263 @@ impl<'w> EntityRef<'w> { /// which is only valid while the `'w` borrow of the lifetime is active. #[inline] pub fn get_by_id(&self, component_id: ComponentId) -> Option> { - // SAFETY: &self implies shared access for duration of returned value - unsafe { self.as_unsafe_world_cell_readonly().get_by_id(component_id) } + // SAFETY: We have read-only access to all components of this entity. + unsafe { self.0.get_by_id(component_id) } + } +} + +impl<'w> From> for EntityRef<'w> { + fn from(entity_mut: EntityWorldMut<'w>) -> EntityRef<'w> { + // SAFETY: + // - `EntityWorldMut` guarantees exclusive access to the entire world. + unsafe { EntityRef::new(entity_mut.into_unsafe_entity_cell()) } + } +} + +impl<'a> From<&'a EntityWorldMut<'_>> for EntityRef<'a> { + fn from(value: &'a EntityWorldMut<'_>) -> Self { + // SAFETY: + // - `EntityWorldMut` guarantees exclusive access to the entire world. + // - `&value` ensures no mutable accesses are active. + unsafe { EntityRef::new(value.as_unsafe_entity_cell_readonly()) } } } impl<'w> From> for EntityRef<'w> { - fn from(entity_mut: EntityMut<'w>) -> EntityRef<'w> { - // SAFETY: the safety invariants on EntityMut and EntityRef are identical - // and EntityMut is promised to be valid by construction. - unsafe { EntityRef::new(entity_mut.world, entity_mut.entity, entity_mut.location) } + fn from(value: EntityMut<'w>) -> Self { + // SAFETY: + // - `EntityMut` gurantees exclusive access to all of the entity's components. + unsafe { EntityRef::new(value.0) } } } -/// A mutable reference to a particular [`Entity`] and all of its components -pub struct EntityMut<'w> { +impl<'a> From<&'a EntityMut<'_>> for EntityRef<'a> { + fn from(value: &'a EntityMut<'_>) -> Self { + // SAFETY: + // - `EntityMut` gurantees exclusive access to all of the entity's components. + // - `&value` ensures there are no mutable accesses. + unsafe { EntityRef::new(value.0) } + } +} + +/// Provides mutable access to a single entity and all of its components. +/// +/// Contrast with [`EntityWorldMut`], with allows adding and removing components, +/// despawning the entity, and provides mutable access to the entire world. +/// Because of this, `EntityWorldMut` cannot coexist with any other world accesses. +/// +/// # Examples +/// +/// Disjoint mutable access. +/// +/// ``` +/// # use bevy_ecs::prelude::*; +/// # #[derive(Component)] pub struct A; +/// fn disjoint_system( +/// query1: Query>, +/// query2: Query>, +/// ) { +/// // ... +/// } +/// # bevy_ecs::system::assert_is_system(disjoint_system); +/// ``` +pub struct EntityMut<'w>(UnsafeEntityCell<'w>); + +impl<'w> EntityMut<'w> { + /// # Safety + /// - `cell` must have permission to mutate every component of the entity. + /// - No accesses to any of the entity's components may exist + /// at the same time as the returned [`EntityMut`]. + pub(crate) unsafe fn new(cell: UnsafeEntityCell<'w>) -> Self { + Self(cell) + } + + /// Returns a new instance with a shorter lifetime. + /// This is useful if you have `&mut EntityMut`, but you need `EntityMut`. + pub fn reborrow(&mut self) -> EntityMut<'_> { + // SAFETY: We have exclusive access to the entire entity and its components. + unsafe { Self::new(self.0) } + } + + /// Gets read-only access to all of the entity's components. + pub fn as_readonly(&self) -> EntityRef<'_> { + EntityRef::from(self) + } + + /// Returns the [ID](Entity) of the current entity. + #[inline] + #[must_use = "Omit the .id() call if you do not need to store the `Entity` identifier."] + pub fn id(&self) -> Entity { + self.0.id() + } + + /// Gets metadata indicating the location where the current entity is stored. + #[inline] + pub fn location(&self) -> EntityLocation { + self.0.location() + } + + /// Returns the archetype that the current entity belongs to. + #[inline] + pub fn archetype(&self) -> &Archetype { + self.0.archetype() + } + + /// Returns `true` if the current entity has a component of type `T`. + /// Otherwise, this returns `false`. + /// + /// ## Notes + /// + /// If you do not know the concrete type of a component, consider using + /// [`Self::contains_id`] or [`Self::contains_type_id`]. + #[inline] + pub fn contains(&self) -> bool { + self.contains_type_id(TypeId::of::()) + } + + /// Returns `true` if the current entity has a component identified by `component_id`. + /// Otherwise, this returns false. + /// + /// ## Notes + /// + /// - If you know the concrete type of the component, you should prefer [`Self::contains`]. + /// - If you know the component's [`TypeId`] but not its [`ComponentId`], consider using + /// [`Self::contains_type_id`]. + #[inline] + pub fn contains_id(&self, component_id: ComponentId) -> bool { + self.0.contains_id(component_id) + } + + /// Returns `true` if the current entity has a component with the type identified by `type_id`. + /// Otherwise, this returns false. + /// + /// ## Notes + /// + /// - If you know the concrete type of the component, you should prefer [`Self::contains`]. + /// - If you have a [`ComponentId`] instead of a [`TypeId`], consider using [`Self::contains_id`]. + #[inline] + pub fn contains_type_id(&self, type_id: TypeId) -> bool { + self.0.contains_type_id(type_id) + } + + /// Gets access to the component of type `T` for the current entity. + /// Returns `None` if the entity does not have a component of type `T`. + #[inline] + pub fn get(&self) -> Option<&'_ T> { + self.as_readonly().get() + } + + /// Gets access to the component of type `T` for the current entity, + /// including change detection information as a [`Ref`]. + /// + /// Returns `None` if the entity does not have a component of type `T`. + #[inline] + pub fn get_ref(&self) -> Option> { + self.as_readonly().get_ref() + } + + /// Gets mutable access to the component of type `T` for the current entity. + /// Returns `None` if the entity does not have a component of type `T`. + #[inline] + pub fn get_mut(&mut self) -> Option> { + // SAFETY: &mut self implies exclusive access for duration of returned value + unsafe { self.0.get_mut() } + } + + /// Retrieves the change ticks for the given component. This can be useful for implementing change + /// detection in custom runtimes. + #[inline] + pub fn get_change_ticks(&self) -> Option { + self.as_readonly().get_change_ticks::() + } + + /// Retrieves the change ticks for the given [`ComponentId`]. This can be useful for implementing change + /// detection in custom runtimes. + /// + /// **You should prefer to use the typed API [`EntityWorldMut::get_change_ticks`] where possible and only + /// use this in cases where the actual component types are not known at + /// compile time.** + #[inline] + pub fn get_change_ticks_by_id(&self, component_id: ComponentId) -> Option { + self.as_readonly().get_change_ticks_by_id(component_id) + } + + /// Gets the component of the given [`ComponentId`] from the entity. + /// + /// **You should prefer to use the typed API [`EntityWorldMut::get`] where possible and only + /// use this in cases where the actual component types are not known at + /// compile time.** + /// + /// Unlike [`EntityMut::get`], this returns a raw pointer to the component, + /// which is only valid while the [`EntityMut`] is alive. + #[inline] + pub fn get_by_id(&self, component_id: ComponentId) -> Option> { + self.as_readonly().get_by_id(component_id) + } + + /// Gets a [`MutUntyped`] of the component of the given [`ComponentId`] from the entity. + /// + /// **You should prefer to use the typed API [`EntityMut::get_mut`] where possible and only + /// use this in cases where the actual component types are not known at + /// compile time.** + /// + /// Unlike [`EntityMut::get_mut`], this returns a raw pointer to the component, + /// which is only valid while the [`EntityMut`] is alive. + #[inline] + pub fn get_mut_by_id(&mut self, component_id: ComponentId) -> Option> { + // SAFETY: + // - `&mut self` ensures that no references exist to this entity's components. + // - `as_unsafe_world_cell` gives mutable permission for all components on this entity + unsafe { self.0.get_mut_by_id(component_id) } + } +} + +impl<'w> From> for EntityMut<'w> { + fn from(value: EntityWorldMut<'w>) -> Self { + // SAFETY: `EntityWorldMut` guarantees exclusive access to the entire world. + unsafe { EntityMut::new(value.into_unsafe_entity_cell()) } + } +} + +impl<'a> From<&'a mut EntityWorldMut<'_>> for EntityMut<'a> { + fn from(value: &'a mut EntityWorldMut<'_>) -> Self { + // SAFETY: `EntityWorldMut` guarantees exclusive access to the entire world. + unsafe { EntityMut::new(value.as_unsafe_entity_cell()) } + } +} + +/// A mutable reference to a particular [`Entity`], and the entire world. +/// This is essentially a performance-optimized `(Entity, &mut World)` tuple, +/// which caches the [`EntityLocation`] to reduce duplicate lookups. +/// +/// Since this type provides mutable access to the entire world, only one +/// [`EntityWorldMut`] can exist at a time for a given world. +/// +/// See also [`EntityMut`], which allows disjoint mutable access to multiple +/// entities at once. Unlike `EntityMut`, this type allows adding and +/// removing components, and despawning the entity. +pub struct EntityWorldMut<'w> { world: &'w mut World, entity: Entity, location: EntityLocation, } -impl<'w> EntityMut<'w> { - fn as_unsafe_world_cell_readonly(&self) -> UnsafeEntityCell<'_> { +impl<'w> EntityWorldMut<'w> { + fn as_unsafe_entity_cell_readonly(&self) -> UnsafeEntityCell<'_> { UnsafeEntityCell::new( self.world.as_unsafe_world_cell_readonly(), self.entity, self.location, ) } - fn as_unsafe_world_cell(&mut self) -> UnsafeEntityCell<'_> { + fn as_unsafe_entity_cell(&mut self) -> UnsafeEntityCell<'_> { + UnsafeEntityCell::new( + self.world.as_unsafe_world_cell(), + self.entity, + self.location, + ) + } + fn into_unsafe_entity_cell(self) -> UnsafeEntityCell<'w> { UnsafeEntityCell::new( self.world.as_unsafe_world_cell(), self.entity, @@ -217,7 +428,7 @@ impl<'w> EntityMut<'w> { debug_assert!(world.entities().contains(entity)); debug_assert_eq!(world.entities().get(entity), Some(location)); - EntityMut { + EntityWorldMut { world, entity, location, @@ -265,7 +476,7 @@ impl<'w> EntityMut<'w> { /// [`Self::contains_type_id`]. #[inline] pub fn contains_id(&self, component_id: ComponentId) -> bool { - self.as_unsafe_world_cell_readonly() + self.as_unsafe_entity_cell_readonly() .contains_id(component_id) } @@ -278,7 +489,7 @@ impl<'w> EntityMut<'w> { /// - If you have a [`ComponentId`] instead of a [`TypeId`], consider using [`Self::contains_id`]. #[inline] pub fn contains_type_id(&self, type_id: TypeId) -> bool { - self.as_unsafe_world_cell_readonly() + self.as_unsafe_entity_cell_readonly() .contains_type_id(type_id) } @@ -286,8 +497,16 @@ impl<'w> EntityMut<'w> { /// Returns `None` if the entity does not have a component of type `T`. #[inline] pub fn get(&self) -> Option<&'_ T> { - // SAFETY: &self implies shared access for duration of returned value - unsafe { self.as_unsafe_world_cell_readonly().get::() } + EntityRef::from(self).get() + } + + /// Gets access to the component of type `T` for the current entity, + /// including change detection information as a [`Ref`]. + /// + /// Returns `None` if the entity does not have a component of type `T`. + #[inline] + pub fn get_ref(&self) -> Option> { + EntityRef::from(self).get_ref() } /// Gets mutable access to the component of type `T` for the current entity. @@ -295,30 +514,54 @@ impl<'w> EntityMut<'w> { #[inline] pub fn get_mut(&mut self) -> Option> { // SAFETY: &mut self implies exclusive access for duration of returned value - unsafe { self.as_unsafe_world_cell().get_mut() } + unsafe { self.as_unsafe_entity_cell().get_mut() } } /// Retrieves the change ticks for the given component. This can be useful for implementing change /// detection in custom runtimes. #[inline] pub fn get_change_ticks(&self) -> Option { - // SAFETY: &self implies shared access - unsafe { self.as_unsafe_world_cell_readonly().get_change_ticks::() } + EntityRef::from(self).get_change_ticks::() } /// Retrieves the change ticks for the given [`ComponentId`]. This can be useful for implementing change /// detection in custom runtimes. /// - /// **You should prefer to use the typed API [`EntityMut::get_change_ticks`] where possible and only + /// **You should prefer to use the typed API [`EntityWorldMut::get_change_ticks`] where possible and only /// use this in cases where the actual component types are not known at /// compile time.** #[inline] pub fn get_change_ticks_by_id(&self, component_id: ComponentId) -> Option { - // SAFETY: &self implies shared access - unsafe { - self.as_unsafe_world_cell_readonly() - .get_change_ticks_by_id(component_id) - } + EntityRef::from(self).get_change_ticks_by_id(component_id) + } + + /// Gets the component of the given [`ComponentId`] from the entity. + /// + /// **You should prefer to use the typed API [`EntityWorldMut::get`] where possible and only + /// use this in cases where the actual component types are not known at + /// compile time.** + /// + /// Unlike [`EntityWorldMut::get`], this returns a raw pointer to the component, + /// which is only valid while the [`EntityWorldMut`] is alive. + #[inline] + pub fn get_by_id(&self, component_id: ComponentId) -> Option> { + EntityRef::from(self).get_by_id(component_id) + } + + /// Gets a [`MutUntyped`] of the component of the given [`ComponentId`] from the entity. + /// + /// **You should prefer to use the typed API [`EntityWorldMut::get_mut`] where possible and only + /// use this in cases where the actual component types are not known at + /// compile time.** + /// + /// Unlike [`EntityWorldMut::get_mut`], this returns a raw pointer to the component, + /// which is only valid while the [`EntityWorldMut`] is alive. + #[inline] + pub fn get_mut_by_id(&mut self, component_id: ComponentId) -> Option> { + // SAFETY: + // - `&mut self` ensures that no references exist to this entity's components. + // - `as_unsafe_world_cell` gives mutable permission for all components on this entity + unsafe { self.as_unsafe_entity_cell().get_mut_by_id(component_id) } } /// Adds a [`Bundle`] of components to the entity. @@ -350,11 +593,11 @@ impl<'w> EntityMut<'w> { /// /// This will overwrite any previous value(s) of the same component type. /// - /// You should prefer to use the typed API [`EntityMut::insert`] where possible. + /// You should prefer to use the typed API [`EntityWorldMut::insert`] where possible. /// /// # Safety /// - /// - [`ComponentId`] must be from the same world as [`EntityMut`] + /// - [`ComponentId`] must be from the same world as [`EntityWorldMut`] /// - [`OwningPtr`] must be a valid reference to the type represented by [`ComponentId`] pub unsafe fn insert_by_id( &mut self, @@ -391,13 +634,13 @@ impl<'w> EntityMut<'w> { /// /// This will overwrite any previous value(s) of the same component type. /// - /// You should prefer to use the typed API [`EntityMut::insert`] where possible. - /// If your [`Bundle`] only has one component, use the cached API [`EntityMut::insert_by_id`]. + /// You should prefer to use the typed API [`EntityWorldMut::insert`] where possible. + /// If your [`Bundle`] only has one component, use the cached API [`EntityWorldMut::insert_by_id`]. /// /// If possible, pass a sorted slice of `ComponentId` to maximize caching potential. /// /// # Safety - /// - Each [`ComponentId`] must be from the same world as [`EntityMut`] + /// - Each [`ComponentId`] must be from the same world as [`EntityWorldMut`] /// - Each [`OwningPtr`] must be a valid reference to the type represented by [`ComponentId`] pub unsafe fn insert_by_ids<'a, I: Iterator>>( &mut self, @@ -719,27 +962,27 @@ impl<'w> EntityMut<'w> { self.world } - /// Returns this `EntityMut`'s world. + /// Returns this entity's world. /// - /// See [`EntityMut::world_scope`] or [`EntityMut::into_world_mut`] for a safe alternative. + /// See [`EntityWorldMut::world_scope`] or [`EntityWorldMut::into_world_mut`] for a safe alternative. /// /// # Safety /// Caller must not modify the world in a way that changes the current entity's location /// If the caller _does_ do something that could change the location, `self.update_location()` - /// must be called before using any other methods on this [`EntityMut`]. + /// must be called before using any other methods on this [`EntityWorldMut`]. #[inline] pub unsafe fn world_mut(&mut self) -> &mut World { self.world } - /// Returns this `EntityMut`'s [`World`], consuming itself. + /// Returns this entity's [`World`], consuming itself. #[inline] pub fn into_world_mut(self) -> &'w mut World { self.world } - /// Gives mutable access to this `EntityMut`'s [`World`] in a temporary scope. - /// This is a safe alternative to using [`Self::world_mut`]. + /// Gives mutable access to this entity's [`World`] in a temporary scope. + /// This is a safe alternative to using [`EntityWorldMut::world_mut`]. /// /// # Examples /// @@ -757,14 +1000,14 @@ impl<'w> EntityMut<'w> { /// let mut r = world.resource_mut::(); /// r.0 += 1; /// - /// // Return a value from the world before giving it back to the `EntityMut`. + /// // Return a value from the world before giving it back to the `EntityWorldMut`. /// *r /// }); /// # assert_eq!(new_r.0, 1); /// ``` pub fn world_scope(&mut self, f: impl FnOnce(&mut World) -> U) -> U { struct Guard<'w, 'a> { - entity_mut: &'a mut EntityMut<'w>, + entity_mut: &'a mut EntityWorldMut<'w>, } impl Drop for Guard<'_, '_> { @@ -784,47 +1027,13 @@ impl<'w> EntityMut<'w> { /// Updates the internal entity location to match the current location in the internal /// [`World`]. /// - /// This is *only* required when using the unsafe function [`EntityMut::world_mut`], + /// This is *only* required when using the unsafe function [`EntityWorldMut::world_mut`], /// which enables the location to change. pub fn update_location(&mut self) { self.location = self.world.entities().get(self.entity).unwrap(); } } -impl<'w> EntityMut<'w> { - /// Gets the component of the given [`ComponentId`] from the entity. - /// - /// **You should prefer to use the typed API [`EntityMut::get`] where possible and only - /// use this in cases where the actual component types are not known at - /// compile time.** - /// - /// Unlike [`EntityMut::get`], this returns a raw pointer to the component, - /// which is only valid while the [`EntityMut`] is alive. - #[inline] - pub fn get_by_id(&self, component_id: ComponentId) -> Option> { - // SAFETY: - // - `&self` ensures that no mutable references exist to this entity's components. - // - `as_unsafe_world_cell_readonly` gives read only permission for all components on this entity - unsafe { self.as_unsafe_world_cell_readonly().get_by_id(component_id) } - } - - /// Gets a [`MutUntyped`] of the component of the given [`ComponentId`] from the entity. - /// - /// **You should prefer to use the typed API [`EntityMut::get_mut`] where possible and only - /// use this in cases where the actual component types are not known at - /// compile time.** - /// - /// Unlike [`EntityMut::get_mut`], this returns a raw pointer to the component, - /// which is only valid while the [`EntityMut`] is alive. - #[inline] - pub fn get_mut_by_id(&mut self, component_id: ComponentId) -> Option> { - // SAFETY: - // - `&mut self` ensures that no references exist to this entity's components. - // - `as_unsafe_world_cell` gives mutable permission for all components on this entity - unsafe { self.as_unsafe_world_cell().get_mut_by_id(component_id) } - } -} - /// Inserts a dynamic [`Bundle`] into the entity. /// /// # Safety @@ -1027,9 +1236,7 @@ mod tests { use bevy_ptr::OwningPtr; use std::panic::AssertUnwindSafe; - use crate as bevy_ecs; - use crate::component::ComponentId; - use crate::prelude::*; // for the `#[derive(Component)]` + use crate::{self as bevy_ecs, component::ComponentId, prelude::*, system::assert_is_system}; #[test] fn sorted_remove() { @@ -1090,7 +1297,7 @@ mod tests { { test_component.set_changed(); let test_component = - // SAFETY: `test_component` has unique access of the `EntityMut` and is not used afterwards + // SAFETY: `test_component` has unique access of the `EntityWorldMut` and is not used afterwards unsafe { test_component.into_inner().deref_mut::() }; test_component.0 = 43; } @@ -1133,7 +1340,7 @@ mod tests { let id = entity.id(); let res = std::panic::catch_unwind(AssertUnwindSafe(|| { entity.world_scope(|w| { - // Change the entity's `EntityLocation`, which invalidates the original `EntityMut`. + // Change the entity's `EntityLocation`, which invalidates the original `EntityWorldMut`. // This will get updated at the end of the scope. w.entity_mut(id).insert(TestComponent(0)); @@ -1369,4 +1576,113 @@ mod tests { assert_eq!(dynamic_components, static_components); } + + #[derive(Component)] + struct A; + + #[derive(Resource)] + struct R; + + #[test] + fn disjoint_access() { + fn disjoint_readonly(_: Query>, _: Query>) {} + + fn disjoint_mutable(_: Query>, _: Query>) {} + + assert_is_system(disjoint_readonly); + assert_is_system(disjoint_mutable); + } + + #[test] + fn ref_compatible() { + fn borrow_system(_: Query<(EntityRef, &A)>, _: Query<&A>) {} + + assert_is_system(borrow_system); + } + + #[test] + fn ref_compatible_with_resource() { + fn borrow_system(_: Query, _: Res) {} + + assert_is_system(borrow_system); + } + + #[test] + #[ignore] // This should pass, but it currently fails due to limitations in our access model. + fn ref_compatible_with_resource_mut() { + fn borrow_system(_: Query, _: ResMut) {} + + assert_is_system(borrow_system); + } + + #[test] + #[should_panic] + fn ref_incompatible_with_mutable_component() { + fn incompatible_system(_: Query<(EntityRef, &mut A)>) {} + + assert_is_system(incompatible_system); + } + + #[test] + #[should_panic] + fn ref_incompatible_with_mutable_query() { + fn incompatible_system(_: Query, _: Query<&mut A>) {} + + assert_is_system(incompatible_system); + } + + #[test] + fn mut_compatible_with_entity() { + fn borrow_mut_system(_: Query<(Entity, EntityMut)>) {} + + assert_is_system(borrow_mut_system); + } + + #[test] + #[ignore] // This should pass, but it currently fails due to limitations in our access model. + fn mut_compatible_with_resource() { + fn borrow_mut_system(_: Res, _: Query) {} + + assert_is_system(borrow_mut_system); + } + + #[test] + #[ignore] // This should pass, but it currently fails due to limitations in our access model. + fn mut_compatible_with_resource_mut() { + fn borrow_mut_system(_: ResMut, _: Query) {} + + assert_is_system(borrow_mut_system); + } + + #[test] + #[should_panic] + fn mut_incompatible_with_read_only_component() { + fn incompatible_system(_: Query<(EntityMut, &A)>) {} + + assert_is_system(incompatible_system); + } + + #[test] + #[should_panic] + fn mut_incompatible_with_mutable_component() { + fn incompatible_system(_: Query<(EntityMut, &mut A)>) {} + + assert_is_system(incompatible_system); + } + + #[test] + #[should_panic] + fn mut_incompatible_with_read_only_query() { + fn incompatible_system(_: Query, _: Query<&A>) {} + + assert_is_system(incompatible_system); + } + + #[test] + #[should_panic] + fn mut_incompatible_with_mutable_query() { + fn incompatible_system(_: Query, _: Query<&mut A>) {} + + assert_is_system(incompatible_system); + } } diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 0e79b19ce8568..b64eb5a56e50d 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -7,7 +7,7 @@ pub mod unsafe_world_cell; mod world_cell; pub use crate::change_detection::{Mut, Ref, CHECK_TICK_THRESHOLD}; -pub use entity_ref::{EntityMut, EntityRef}; +pub use entity_ref::{EntityMut, EntityRef, EntityWorldMut}; pub use spawn_batch::*; pub use world_cell::*; @@ -18,7 +18,7 @@ use crate::{ component::{Component, ComponentDescriptor, ComponentId, ComponentInfo, Components, Tick}, entity::{AllocAtWithoutReplacement, Entities, Entity, EntityLocation}, event::{Event, Events}, - query::{DebugCheckedUnwrap, QueryState, ReadOnlyWorldQuery, WorldQuery}, + query::{DebugCheckedUnwrap, QueryEntityError, QueryState, ReadOnlyWorldQuery, WorldQuery}, removal_detection::RemovedComponentEvents, schedule::{Schedule, ScheduleLabel, Schedules}, storage::{ResourceData, Storages}, @@ -30,13 +30,14 @@ use bevy_utils::tracing::warn; use std::{ any::TypeId, fmt, + mem::MaybeUninit, sync::atomic::{AtomicU32, Ordering}, }; mod identifier; pub use identifier::WorldId; -use self::unsafe_world_cell::UnsafeWorldCell; +use self::unsafe_world_cell::{UnsafeEntityCell, UnsafeWorldCell}; /// Stores and exposes operations on [entities](Entity), [components](Component), resources, /// and their associated metadata. @@ -256,7 +257,7 @@ impl World { } } - /// Retrieves an [`EntityMut`] that exposes read and write operations for the given `entity`. + /// Retrieves an [`EntityWorldMut`] that exposes read and write operations for the given `entity`. /// This will panic if the `entity` does not exist. Use [`World::get_entity_mut`] if you want /// to check for entity existence instead of implicitly panic-ing. /// @@ -277,7 +278,7 @@ impl World { /// ``` #[inline] #[track_caller] - pub fn entity_mut(&mut self, entity: Entity) -> EntityMut { + pub fn entity_mut(&mut self, entity: Entity) -> EntityWorldMut { #[inline(never)] #[cold] #[track_caller] @@ -291,6 +292,91 @@ impl World { } } + /// Gets an [`EntityRef`] for multiple entities at once. + /// + /// # Panics + /// + /// If any entity does not exist in the world. + /// + /// # Examples + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// # let mut world = World::new(); + /// # let id1 = world.spawn_empty().id(); + /// # let id2 = world.spawn_empty().id(); + /// // Getting multiple entities. + /// let [entity1, entity2] = world.many_entities([id1, id2]); + /// ``` + /// + /// ```should_panic + /// # use bevy_ecs::prelude::*; + /// # let mut world = World::new(); + /// # let id1 = world.spawn_empty().id(); + /// # let id2 = world.spawn_empty().id(); + /// // Trying to get a despawned entity will fail. + /// world.despawn(id2); + /// world.many_entities([id1, id2]); + /// ``` + pub fn many_entities(&mut self, entities: [Entity; N]) -> [EntityRef<'_>; N] { + #[inline(never)] + #[cold] + #[track_caller] + fn panic_no_entity(entity: Entity) -> ! { + panic!("Entity {entity:?} does not exist"); + } + + match self.get_many_entities(entities) { + Ok(refs) => refs, + Err(entity) => panic_no_entity(entity), + } + } + + /// Gets mutable access to multiple entities at once. + /// + /// # Panics + /// + /// If any entities do not exist in the world, + /// or if the same entity is specified multiple times. + /// + /// # Examples + /// + /// Disjoint mutable access. + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// # let mut world = World::new(); + /// # let id1 = world.spawn_empty().id(); + /// # let id2 = world.spawn_empty().id(); + /// // Disjoint mutable access. + /// let [entity1, entity2] = world.many_entities_mut([id1, id2]); + /// ``` + /// + /// Trying to access the same entity multiple times will fail. + /// + /// ```should_panic + /// # use bevy_ecs::prelude::*; + /// # let mut world = World::new(); + /// # let id = world.spawn_empty().id(); + /// world.many_entities_mut([id, id]); + /// ``` + pub fn many_entities_mut( + &mut self, + entities: [Entity; N], + ) -> [EntityMut<'_>; N] { + #[inline(never)] + #[cold] + #[track_caller] + fn panic_on_err(e: QueryEntityError) -> ! { + panic!("{e}"); + } + + match self.get_many_entities_mut(entities) { + Ok(borrows) => borrows, + Err(e) => panic_on_err(e), + } + } + /// Returns the components of an [`Entity`](crate::entity::Entity) through [`ComponentInfo`](crate::component::ComponentInfo). #[inline] pub fn inspect_entity(&self, entity: Entity) -> Vec<&ComponentInfo> { @@ -315,7 +401,7 @@ impl World { .collect() } - /// Returns an [`EntityMut`] for the given `entity` (if it exists) or spawns one if it doesn't exist. + /// Returns an [`EntityWorldMut`] for the given `entity` (if it exists) or spawns one if it doesn't exist. /// This will return [`None`] if the `entity` exists with a different generation. /// /// # Note @@ -323,12 +409,12 @@ impl World { /// 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). #[inline] - pub fn get_or_spawn(&mut self, entity: Entity) -> Option { + pub fn get_or_spawn(&mut self, entity: Entity) -> Option { self.flush(); match self.entities.alloc_at_without_replacement(entity) { AllocAtWithoutReplacement::Exists(location) => { // SAFETY: `entity` exists and `location` is that entity's location - Some(unsafe { EntityMut::new(self, entity, location) }) + Some(unsafe { EntityWorldMut::new(self, entity, location) }) } AllocAtWithoutReplacement::DidNotExist => { // SAFETY: entity was just allocated @@ -339,8 +425,8 @@ impl World { } /// Retrieves an [`EntityRef`] that exposes read-only operations for the given `entity`. - /// Returns [`None`] if the `entity` does not exist. Use [`World::entity`] if you don't want - /// to unwrap the [`EntityRef`] yourself. + /// Returns [`None`] if the `entity` does not exist. + /// Instead of unwrapping the value returned from this function, prefer [`World::entity`]. /// /// ``` /// use bevy_ecs::{component::Component, world::World}; @@ -362,10 +448,48 @@ impl World { let location = self.entities.get(entity)?; // SAFETY: if the Entity is invalid, the function returns early. // Additionally, Entities::get(entity) returns the correct EntityLocation if the entity exists. - let entity_ref = unsafe { EntityRef::new(self, entity, location) }; + let entity_cell = + UnsafeEntityCell::new(self.as_unsafe_world_cell_readonly(), entity, location); + // SAFETY: The UnsafeEntityCell has read access to the entire world. + let entity_ref = unsafe { EntityRef::new(entity_cell) }; Some(entity_ref) } + /// Gets an [`EntityRef`] for multiple entities at once. + /// + /// # Errors + /// + /// If any entity does not exist in the world. + /// + /// # Examples + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// # let mut world = World::new(); + /// # let id1 = world.spawn_empty().id(); + /// # let id2 = world.spawn_empty().id(); + /// // Getting multiple entities. + /// let [entity1, entity2] = world.get_many_entities([id1, id2]).unwrap(); + /// + /// // Trying to get a despawned entity will fail. + /// world.despawn(id2); + /// assert!(world.get_many_entities([id1, id2]).is_err()); + /// ``` + pub fn get_many_entities( + &self, + entities: [Entity; N], + ) -> Result<[EntityRef<'_>; N], Entity> { + let mut refs = [MaybeUninit::uninit(); N]; + for (r, id) in std::iter::zip(&mut refs, entities) { + *r = MaybeUninit::new(self.get_entity(id).ok_or(id)?); + } + + // SAFETY: Each item was initialized in the above loop. + let refs = refs.map(|r| unsafe { MaybeUninit::assume_init(r) }); + + Ok(refs) + } + /// Returns an [`Entity`] iterator of current entities. /// /// This is useful in contexts where you only have read-only access to the [`World`]. @@ -385,15 +509,47 @@ impl World { table_row: archetype_entity.table_row(), }; - // SAFETY: entity exists and location accurately specifies the archetype where the entity is stored - unsafe { EntityRef::new(self, entity, location) } + // SAFETY: entity exists and location accurately specifies the archetype where the entity is stored. + let cell = UnsafeEntityCell::new( + self.as_unsafe_world_cell_readonly(), + entity, + location, + ); + // SAFETY: `&self` gives read access to the entire world. + unsafe { EntityRef::new(cell) } + }) + }) + } + + /// Returns a mutable iterator over all entities in the `World`. + pub fn iter_entities_mut(&mut self) -> impl Iterator> + '_ { + let world_cell = self.as_unsafe_world_cell(); + world_cell.archetypes().iter().flat_map(move |archetype| { + archetype + .entities() + .iter() + .enumerate() + .map(move |(archetype_row, archetype_entity)| { + let entity = archetype_entity.entity(); + let location = EntityLocation { + archetype_id: archetype.id(), + archetype_row: ArchetypeRow::new(archetype_row), + table_id: archetype.table_id(), + table_row: archetype_entity.table_row(), + }; + + // SAFETY: entity exists and location accurately specifies the archetype where the entity is stored. + let cell = UnsafeEntityCell::new(world_cell, entity, location); + // SAFETY: We have exclusive access to the entire world. We only create one borrow for each entity, + // so none will conflict with one another. + unsafe { EntityMut::new(cell) } }) }) } - /// Retrieves an [`EntityMut`] that exposes read and write operations for the given `entity`. - /// Returns [`None`] if the `entity` does not exist. Use [`World::entity_mut`] if you don't want - /// to unwrap the [`EntityMut`] yourself. + /// Retrieves an [`EntityWorldMut`] that exposes read and write operations for the given `entity`. + /// Returns [`None`] if the `entity` does not exist. + /// Instead of unwrapping the value returned from this function, prefer [`World::entity_mut`]. /// /// ``` /// use bevy_ecs::{component::Component, world::World}; @@ -411,13 +567,78 @@ impl World { /// position.x = 1.0; /// ``` #[inline] - pub fn get_entity_mut(&mut self, entity: Entity) -> Option { + pub fn get_entity_mut(&mut self, entity: Entity) -> Option { let location = self.entities.get(entity)?; // SAFETY: `entity` exists and `location` is that entity's location - Some(unsafe { EntityMut::new(self, entity, location) }) + Some(unsafe { EntityWorldMut::new(self, entity, location) }) } - /// Spawns a new [`Entity`] and returns a corresponding [`EntityMut`], which can be used + /// Gets mutable access to multiple entities. + /// + /// # Errors + /// + /// If any entities do not exist in the world, + /// or if the same entity is specified multiple times. + /// + /// # Examples + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// # let mut world = World::new(); + /// # let id1 = world.spawn_empty().id(); + /// # let id2 = world.spawn_empty().id(); + /// // Disjoint mutable access. + /// let [entity1, entity2] = world.get_many_entities_mut([id1, id2]).unwrap(); + /// + /// // Trying to access the same entity multiple times will fail. + /// assert!(world.get_many_entities_mut([id1, id1]).is_err()); + /// ``` + pub fn get_many_entities_mut( + &mut self, + entities: [Entity; N], + ) -> Result<[EntityMut<'_>; N], QueryEntityError> { + // Ensure each entity is unique. + for i in 0..N { + for j in 0..i { + if entities[i] == entities[j] { + return Err(QueryEntityError::AliasedMutability(entities[i])); + } + } + } + + // SAFETY: Each entity is unique. + unsafe { self.get_entities_mut_unchecked(entities) } + } + + /// # Safety + /// `entities` must contain no duplicate [`Entity`] IDs. + unsafe fn get_entities_mut_unchecked( + &mut self, + entities: [Entity; N], + ) -> Result<[EntityMut<'_>; N], QueryEntityError> { + let world_cell = self.as_unsafe_world_cell(); + + let mut cells = [MaybeUninit::uninit(); N]; + for (cell, id) in std::iter::zip(&mut cells, entities) { + *cell = MaybeUninit::new( + world_cell + .get_entity(id) + .ok_or(QueryEntityError::NoSuchEntity(id))?, + ); + } + // SAFETY: Each item was initialized in the loop above. + let cells = cells.map(|c| unsafe { MaybeUninit::assume_init(c) }); + + // SAFETY: + // - `world_cell` has exclusive access to the entire world. + // - The caller ensures that each entity is unique, so none + // of the borrows will conflict with one another. + let borrows = cells.map(|c| unsafe { EntityMut::new(c) }); + + Ok(borrows) + } + + /// Spawns a new [`Entity`] and returns a corresponding [`EntityWorldMut`], which can be used /// to add components to the entity or retrieve its id. /// /// ``` @@ -442,7 +663,7 @@ impl World { /// let position = world.entity(entity).get::().unwrap(); /// assert_eq!(position.x, 0.0); /// ``` - pub fn spawn_empty(&mut self) -> EntityMut { + pub fn spawn_empty(&mut self) -> EntityWorldMut { self.flush(); let entity = self.entities.alloc(); // SAFETY: entity was just allocated @@ -450,7 +671,7 @@ impl World { } /// Spawns a new [`Entity`] with a given [`Bundle`] of [components](`Component`) and returns - /// a corresponding [`EntityMut`], which can be used to add components to the entity or + /// a corresponding [`EntityWorldMut`], which can be used to add components to the entity or /// retrieve its id. /// /// ``` @@ -508,7 +729,7 @@ impl World { /// let position = world.entity(entity).get::().unwrap(); /// assert_eq!(position.x, 2.0); /// ``` - pub fn spawn(&mut self, bundle: B) -> EntityMut { + pub fn spawn(&mut self, bundle: B) -> EntityWorldMut { self.flush(); let change_tick = self.change_tick(); let entity = self.entities.alloc(); @@ -529,12 +750,12 @@ impl World { }; // SAFETY: entity and location are valid, as they were just created above - unsafe { EntityMut::new(self, entity, entity_location) } + unsafe { EntityWorldMut::new(self, entity, entity_location) } } /// # Safety /// must be called on an entity that was just allocated - unsafe fn spawn_at_empty_internal(&mut self, entity: Entity) -> EntityMut { + unsafe fn spawn_at_empty_internal(&mut self, entity: Entity) -> EntityWorldMut { let archetype = self.archetypes.empty_mut(); // PERF: consider avoiding allocating entities in the empty archetype unless needed let table_row = self.storages.tables[archetype.table_id()].allocate(entity); @@ -543,7 +764,7 @@ impl World { let location = archetype.allocate(entity, table_row); // SAFETY: entity index was just allocated self.entities.set(entity.index(), location); - EntityMut::new(self, entity, location) + EntityWorldMut::new(self, entity, location) } /// Spawns a batch of entities with the same component [Bundle] type. Takes a given [Bundle] @@ -2289,6 +2510,54 @@ mod tests { assert_eq!(entity_counters.len(), 0); } + #[test] + fn iterate_entities_mut() { + #[derive(Component, PartialEq, Debug)] + struct A(i32); + + #[derive(Component, PartialEq, Debug)] + struct B(i32); + + let mut world = World::new(); + + let a1 = world.spawn(A(1)).id(); + let a2 = world.spawn(A(2)).id(); + let b1 = world.spawn(B(1)).id(); + let b2 = world.spawn(B(2)).id(); + + for mut entity in world.iter_entities_mut() { + if let Some(mut a) = entity.get_mut::() { + a.0 -= 1; + } + } + assert_eq!(world.entity(a1).get(), Some(&A(0))); + assert_eq!(world.entity(a2).get(), Some(&A(1))); + assert_eq!(world.entity(b1).get(), Some(&B(1))); + assert_eq!(world.entity(b2).get(), Some(&B(2))); + + for mut entity in world.iter_entities_mut() { + if let Some(mut b) = entity.get_mut::() { + b.0 *= 2; + } + } + assert_eq!(world.entity(a1).get(), Some(&A(0))); + assert_eq!(world.entity(a2).get(), Some(&A(1))); + assert_eq!(world.entity(b1).get(), Some(&B(2))); + assert_eq!(world.entity(b2).get(), Some(&B(4))); + + let mut entities = world.iter_entities_mut().collect::>(); + entities.sort_by_key(|e| e.get::().map(|a| a.0).or(e.get::().map(|b| b.0))); + let (a, b) = entities.split_at_mut(2); + std::mem::swap( + &mut a[1].get_mut::().unwrap().0, + &mut b[0].get_mut::().unwrap().0, + ); + assert_eq!(world.entity(a1).get(), Some(&A(0))); + assert_eq!(world.entity(a2).get(), Some(&A(2))); + assert_eq!(world.entity(b1).get(), Some(&B(1))); + assert_eq!(world.entity(b2).get(), Some(&B(4))); + } + #[test] fn spawn_empty_bundle() { let mut world = World::new(); diff --git a/crates/bevy_hierarchy/src/child_builder.rs b/crates/bevy_hierarchy/src/child_builder.rs index 19bada425f03b..da52ac385faf2 100644 --- a/crates/bevy_hierarchy/src/child_builder.rs +++ b/crates/bevy_hierarchy/src/child_builder.rs @@ -4,7 +4,7 @@ use bevy_ecs::{ entity::Entity, prelude::Events, system::{Command, Commands, EntityCommands}, - world::{EntityMut, World}, + world::{EntityWorldMut, World}, }; use smallvec::SmallVec; @@ -460,7 +460,7 @@ pub struct WorldChildBuilder<'w> { impl<'w> WorldChildBuilder<'w> { /// Spawns an entity with the given bundle and inserts it into the parent entity's [`Children`]. /// Also adds [`Parent`] component to the created entity. - pub fn spawn(&mut self, bundle: impl Bundle + Send + Sync + 'static) -> EntityMut<'_> { + pub fn spawn(&mut self, bundle: impl Bundle + Send + Sync + 'static) -> EntityWorldMut<'_> { let entity = self.world.spawn((bundle, Parent(self.parent))).id(); push_child_unchecked(self.world, self.parent, entity); push_events( @@ -475,7 +475,7 @@ impl<'w> WorldChildBuilder<'w> { /// Spawns an [`Entity`] with no components and inserts it into the parent entity's [`Children`]. /// Also adds [`Parent`] component to the created entity. - pub fn spawn_empty(&mut self) -> EntityMut<'_> { + pub fn spawn_empty(&mut self) -> EntityWorldMut<'_> { let entity = self.world.spawn(Parent(self.parent)).id(); push_child_unchecked(self.world, self.parent, entity); push_events( @@ -554,7 +554,7 @@ pub trait BuildWorldChildren { fn remove_parent(&mut self) -> &mut Self; } -impl<'w> BuildWorldChildren for EntityMut<'w> { +impl<'w> BuildWorldChildren for EntityWorldMut<'w> { fn with_children(&mut self, spawn_children: impl FnOnce(&mut WorldChildBuilder)) -> &mut Self { let parent = self.id(); self.world_scope(|world| { diff --git a/crates/bevy_hierarchy/src/hierarchy.rs b/crates/bevy_hierarchy/src/hierarchy.rs index 32c2f788d63aa..79b56b9fd183a 100644 --- a/crates/bevy_hierarchy/src/hierarchy.rs +++ b/crates/bevy_hierarchy/src/hierarchy.rs @@ -2,7 +2,7 @@ use crate::components::{Children, Parent}; use bevy_ecs::{ entity::Entity, system::{Command, EntityCommands}, - world::{EntityMut, World}, + world::{EntityWorldMut, World}, }; use bevy_utils::tracing::debug; @@ -103,7 +103,7 @@ impl<'w, 's, 'a> DespawnRecursiveExt for EntityCommands<'w, 's, 'a> { } } -impl<'w> DespawnRecursiveExt for EntityMut<'w> { +impl<'w> DespawnRecursiveExt for EntityWorldMut<'w> { /// Despawns the provided entity and its children. fn despawn_recursive(self) { let entity = self.id();