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:
parent
33fdc5f5db
commit
bc8bf34818
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -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)]
|
||||
|
||||
@ -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> {
|
||||
|
||||
@ -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,
|
||||
) {
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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| {
|
||||
|
||||
@ -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();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user