Allow disjoint mutable world access via EntityMut (#9419)

# Objective

Fix #4278
Fix #5504
Fix #9422

Provide safe ways to borrow an entire entity, while allowing disjoint
mutable access. `EntityRef` and `EntityMut` are not suitable for this,
since they provide access to the entire world -- they are just helper
types for working with `&World`/`&mut World`.

This has potential uses for reflection and serialization

## Solution

Remove `EntityRef::world`, which allows it to soundly be used within
queries.

`EntityMut` no longer supports structural world mutations, which allows
multiple instances of it to exist for different entities at once.
Structural world mutations are performed using the new type
`EntityWorldMut`.

```rust
fn disjoint_system(
     q2: Query<&mut A>,
     q1: Query<EntityMut, Without<A>>,
) { ... }

let [entity1, entity2] = world.many_entities_mut([id1, id2]);
*entity1.get_mut::<T>().unwrap() = *entity2.get().unwrap();

for entity in world.iter_entities_mut() {
    ...
}
```

---

## Changelog

- Removed `EntityRef::world`, to fix a soundness issue with queries.
+ Removed the ability to structurally mutate the world using
`EntityMut`, which allows it to be used in queries.
+ Added `EntityWorldMut`, which is used to perform structural mutations
that are no longer allowed using `EntityMut`.

## Migration Guide

**Note for maintainers: ensure that the guide for #9604 is updated
accordingly.**

Removed the method `EntityRef::world`, to fix a soundness issue with
queries. If you need access to `&World` while using an `EntityRef`,
consider passing the world as a separate parameter.

`EntityMut` can no longer perform 'structural' world mutations, such as
adding or removing components, or despawning the entity. Additionally,
`EntityMut::world`, `EntityMut::world_mut` , and
`EntityMut::world_scope` have been removed.
Instead, use the newly-added type `EntityWorldMut`, which is a helper
type for working with `&mut World`.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
This commit is contained in:
Joseph 2023-08-28 16:30:59 -07:00 committed by GitHub
parent 33fdc5f5db
commit bc8bf34818
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 947 additions and 227 deletions

View File

@ -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<ArchetypeId> {
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<Option<ArchetypeId>> {
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<Option<ArchetypeId>> {
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,

View File

@ -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

View File

@ -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},
};
}

View File

@ -53,9 +53,12 @@ pub struct Access<T: SparseSetIndex> {
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<T>,
}
@ -68,6 +71,7 @@ impl<T: SparseSetIndex + fmt::Debug> fmt::Debug for Access<T> {
)
.field("writes", &FormattedBitSet::<T>::new(&self.writes))
.field("reads_all", &self.reads_all)
.field("writes_all", &self.writes_all)
.finish()
}
}
@ -83,6 +87,7 @@ impl<T: SparseSetIndex> Access<T> {
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<T: SparseSetIndex> Access<T> {
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<T: SparseSetIndex> Access<T> {
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<T: SparseSetIndex> Access<T> {
/// Adds all access from `other`.
pub fn extend(&mut self, other: &Access<T>) {
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<T: SparseSetIndex> Access<T> {
/// [`Access`] instances are incompatible if one can write
/// an element that the other can read or write.
pub fn is_compatible(&self, other: &Access<T>) -> 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<T: SparseSetIndex> Access<T> {
pub fn get_conflicts(&self, other: &Access<T>) -> Vec<T> {
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<T: SparseSetIndex> FilteredAccess<T> {
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)]

View File

@ -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<ComponentId>) {
@ -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<ComponentId>) {
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<ArchetypeComponentId>,
) {
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> {

View File

@ -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<dyn Reflect>,
/// 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<B: Bundle + Reflect + FromWorld> FromType<B> for ReflectBundle {
}
}
fn insert_field<B: 'static>(entity: &mut EntityMut, field: &dyn Reflect, registry: &TypeRegistry) {
fn insert_field<B: 'static>(
entity: &mut EntityWorldMut,
field: &dyn Reflect,
registry: &TypeRegistry,
) {
if let Some(reflect_component) = registry.get_type_data::<ReflectComponent>(field.type_id()) {
reflect_component.apply(entity, field);
} else if let Some(reflect_bundle) = registry.get_type_data::<ReflectBundle>(field.type_id()) {
@ -192,7 +201,7 @@ fn insert_field<B: 'static>(entity: &mut EntityMut, field: &dyn Reflect, registr
}
fn apply_or_insert_field<B: 'static>(
entity: &mut EntityMut,
entity: &mut EntityWorldMut,
field: &dyn Reflect,
registry: &TypeRegistry,
) {

View File

@ -25,7 +25,7 @@
//! implementation of `ReflectComponent`.
//!
//! The `FromType<C>` 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::<C>()` 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<dyn Reflect>,
/// 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<Mut<'a, dyn Reflect>>,
pub reflect_mut: for<'a> fn(&'a mut EntityWorldMut<'_>) -> Option<Mut<'a, dyn Reflect>>,
/// 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<Mut<'a, dyn Reflect>> {
pub fn reflect_mut<'a>(
&self,
entity: &'a mut EntityWorldMut<'_>,
) -> Option<Mut<'a, dyn Reflect>> {
(self.0.reflect_mut)(entity)
}

View File

@ -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<F> 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));

View File

@ -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<EntityRef, Without<A>>,
/// ) {
/// // ...
/// }
/// # 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<T: Component>(&self) -> Option<&'w T> {
// SAFETY: &self implies shared access for duration of returned value
unsafe { self.as_unsafe_world_cell_readonly().get::<T>() }
// SAFETY: We have read-only access to all components of this entity.
unsafe { self.0.get::<T>() }
}
/// 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<T: Component>(&self) -> Option<Ref<'w, T>> {
// SAFETY: &self implies shared access for duration of returned value
unsafe { self.as_unsafe_world_cell_readonly().get_ref::<T>() }
// SAFETY: We have read-only access to all components of this entity.
unsafe { self.0.get_ref::<T>() }
}
/// 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<T: Component>(&self) -> Option<ComponentTicks> {
// SAFETY: &self implies shared access
unsafe { self.as_unsafe_world_cell_readonly().get_change_ticks::<T>() }
// SAFETY: We have read-only access to all components of this entity.
unsafe { self.0.get_change_ticks::<T>() }
}
/// 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<ComponentTicks> {
// 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<Ptr<'w>> {
// 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<EntityWorldMut<'w>> 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<EntityMut<'w>> 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<EntityMut, With<A>>,
/// query2: Query<EntityMut, Without<A>>,
/// ) {
/// // ...
/// }
/// # 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<T: Component>(&self) -> bool {
self.contains_type_id(TypeId::of::<T>())
}
/// 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<T: Component>(&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<T: Component>(&self) -> Option<Ref<'_, T>> {
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<T: Component>(&mut self) -> Option<Mut<'_, T>> {
// 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<T: Component>(&self) -> Option<ComponentTicks> {
self.as_readonly().get_change_ticks::<T>()
}
/// 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<ComponentTicks> {
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<Ptr<'_>> {
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<MutUntyped<'_>> {
// 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<EntityWorldMut<'w>> 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<T: Component>(&self) -> Option<&'_ T> {
// SAFETY: &self implies shared access for duration of returned value
unsafe { self.as_unsafe_world_cell_readonly().get::<T>() }
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<T: Component>(&self) -> Option<Ref<'_, T>> {
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<T: Component>(&mut self) -> Option<Mut<'_, T>> {
// 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<T: Component>(&self) -> Option<ComponentTicks> {
// SAFETY: &self implies shared access
unsafe { self.as_unsafe_world_cell_readonly().get_change_ticks::<T>() }
EntityRef::from(self).get_change_ticks::<T>()
}
/// 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<ComponentTicks> {
// 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<Ptr<'_>> {
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<MutUntyped<'_>> {
// 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<Item = OwningPtr<'a>>>(
&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>();
/// 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<U>(&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<Ptr<'_>> {
// 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<MutUntyped<'_>> {
// 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::<TestComponent>() };
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<EntityMut, With<A>>, _: Query<EntityRef, Without<A>>) {}
fn disjoint_mutable(_: Query<EntityMut, With<A>>, _: Query<EntityMut, Without<A>>) {}
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<EntityRef>, _: Res<R>) {}
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<EntityRef>, _: ResMut<R>) {}
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<EntityRef>, _: 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<R>, _: Query<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_mut() {
fn borrow_mut_system(_: ResMut<R>, _: Query<EntityMut>) {}
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<EntityMut>, _: Query<&A>) {}
assert_is_system(incompatible_system);
}
#[test]
#[should_panic]
fn mut_incompatible_with_mutable_query() {
fn incompatible_system(_: Query<EntityMut>, _: Query<&mut A>) {}
assert_is_system(incompatible_system);
}
}

View File

@ -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<const N: usize>(&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<const N: usize>(
&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<EntityMut> {
pub fn get_or_spawn(&mut self, entity: Entity) -> Option<EntityWorldMut> {
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<const N: usize>(
&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) }
})
})
}
/// 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.
/// Returns a mutable iterator over all entities in the `World`.
pub fn iter_entities_mut(&mut self) -> impl Iterator<Item = EntityMut<'_>> + '_ {
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 [`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<EntityMut> {
pub fn get_entity_mut(&mut self, entity: Entity) -> Option<EntityWorldMut> {
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<const N: usize>(
&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<const N: usize>(
&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::<Position>().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::<Position>().unwrap();
/// assert_eq!(position.x, 2.0);
/// ```
pub fn spawn<B: Bundle>(&mut self, bundle: B) -> EntityMut {
pub fn spawn<B: Bundle>(&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]
@ -2284,6 +2505,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>() {
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>() {
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::<Vec<_>>();
entities.sort_by_key(|e| e.get::<A>().map(|a| a.0).or(e.get::<B>().map(|b| b.0)));
let (a, b) = entities.split_at_mut(2);
std::mem::swap(
&mut a[1].get_mut::<A>().unwrap().0,
&mut b[0].get_mut::<B>().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();

View File

@ -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| {

View File

@ -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();