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 {
|
impl Edges {
|
||||||
/// Checks the cache for the target archetype when adding a bundle to the
|
/// 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
|
/// If this returns `None`, it means there has not been a transition from
|
||||||
/// the source archetype via the provided bundle.
|
/// the source archetype via the provided bundle.
|
||||||
///
|
///
|
||||||
/// [`EntityMut::insert`]: crate::world::EntityMut::insert
|
/// [`EntityWorldMut::insert`]: crate::world::EntityWorldMut::insert
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_add_bundle(&self, bundle_id: BundleId) -> Option<ArchetypeId> {
|
pub fn get_add_bundle(&self, bundle_id: BundleId) -> Option<ArchetypeId> {
|
||||||
self.get_add_bundle_internal(bundle_id)
|
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.
|
/// 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]
|
#[inline]
|
||||||
pub(crate) fn insert_add_bundle(
|
pub(crate) fn insert_add_bundle(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -197,7 +197,7 @@ impl Edges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Checks the cache for the target archetype when removing a bundle to the
|
/// 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
|
/// If this returns `None`, it means there has not been a transition from
|
||||||
/// the source archetype via the provided bundle.
|
/// 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
|
/// If this returns `Some(None)`, it means that the bundle cannot be removed
|
||||||
/// from the source archetype.
|
/// from the source archetype.
|
||||||
///
|
///
|
||||||
/// [`EntityMut::remove`]: crate::world::EntityMut::remove
|
/// [`EntityWorldMut::remove`]: crate::world::EntityWorldMut::remove
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_remove_bundle(&self, bundle_id: BundleId) -> Option<Option<ArchetypeId>> {
|
pub fn get_remove_bundle(&self, bundle_id: BundleId) -> Option<Option<ArchetypeId>> {
|
||||||
self.remove_bundle.get(bundle_id).cloned()
|
self.remove_bundle.get(bundle_id).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Caches the target archetype when removing a bundle to the source archetype.
|
/// 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]
|
#[inline]
|
||||||
pub(crate) fn insert_remove_bundle(
|
pub(crate) fn insert_remove_bundle(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -225,21 +225,21 @@ impl Edges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Checks the cache for the target archetype when removing a bundle to the
|
/// 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
|
/// If this returns `None`, it means there has not been a transition from
|
||||||
/// the source archetype via the provided bundle.
|
/// the source archetype via the provided bundle.
|
||||||
///
|
///
|
||||||
/// [`EntityMut::remove`]: crate::world::EntityMut::remove
|
/// [`EntityWorldMut::remove`]: crate::world::EntityWorldMut::remove
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_take_bundle(&self, bundle_id: BundleId) -> Option<Option<ArchetypeId>> {
|
pub fn get_take_bundle(&self, bundle_id: BundleId) -> Option<Option<ArchetypeId>> {
|
||||||
self.take_bundle.get(bundle_id).cloned()
|
self.take_bundle.get(bundle_id).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Caches the target archetype when removing a bundle to the source archetype.
|
/// 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]
|
#[inline]
|
||||||
pub(crate) fn insert_take_bundle(
|
pub(crate) fn insert_take_bundle(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|||||||
@ -21,8 +21,8 @@
|
|||||||
//! |Spawn an entity with components|[`Commands::spawn`]|[`World::spawn`]|
|
//! |Spawn an entity with components|[`Commands::spawn`]|[`World::spawn`]|
|
||||||
//! |Spawn an entity without components|[`Commands::spawn_empty`]|[`World::spawn_empty`]|
|
//! |Spawn an entity without components|[`Commands::spawn_empty`]|[`World::spawn_empty`]|
|
||||||
//! |Despawn an entity|[`EntityCommands::despawn`]|[`World::despawn`]|
|
//! |Despawn an entity|[`EntityCommands::despawn`]|[`World::despawn`]|
|
||||||
//! |Insert a component, bundle, or tuple of components and bundles to an entity|[`EntityCommands::insert`]|[`EntityMut::insert`]|
|
//! |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`]|[`EntityMut::remove`]|
|
//! |Remove a component, bundle, or tuple of components and bundles from an entity|[`EntityCommands::remove`]|[`EntityWorldMut::remove`]|
|
||||||
//!
|
//!
|
||||||
//! [`World`]: crate::world::World
|
//! [`World`]: crate::world::World
|
||||||
//! [`Commands::spawn`]: crate::system::Commands::spawn
|
//! [`Commands::spawn`]: crate::system::Commands::spawn
|
||||||
@ -33,8 +33,8 @@
|
|||||||
//! [`World::spawn`]: crate::world::World::spawn
|
//! [`World::spawn`]: crate::world::World::spawn
|
||||||
//! [`World::spawn_empty`]: crate::world::World::spawn_empty
|
//! [`World::spawn_empty`]: crate::world::World::spawn_empty
|
||||||
//! [`World::despawn`]: crate::world::World::despawn
|
//! [`World::despawn`]: crate::world::World::despawn
|
||||||
//! [`EntityMut::insert`]: crate::world::EntityMut::insert
|
//! [`EntityWorldMut::insert`]: crate::world::EntityWorldMut::insert
|
||||||
//! [`EntityMut::remove`]: crate::world::EntityMut::remove
|
//! [`EntityWorldMut::remove`]: crate::world::EntityWorldMut::remove
|
||||||
mod map_entities;
|
mod map_entities;
|
||||||
|
|
||||||
pub use map_entities::*;
|
pub use map_entities::*;
|
||||||
@ -72,7 +72,7 @@ type IdCursor = isize;
|
|||||||
/// # Usage
|
/// # Usage
|
||||||
///
|
///
|
||||||
/// This data type is returned by iterating a `Query` that has `Entity` as part of its query fetch type parameter ([learn more]).
|
/// 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::*;
|
/// # use bevy_ecs::prelude::*;
|
||||||
@ -84,7 +84,7 @@ type IdCursor = isize;
|
|||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn exclusive_system(world: &mut World) {
|
/// fn exclusive_system(world: &mut World) {
|
||||||
/// // Calling `spawn` returns `EntityMut`.
|
/// // Calling `spawn` returns `EntityWorldMut`.
|
||||||
/// let entity = world.spawn(SomeComponent).id();
|
/// let entity = world.spawn(SomeComponent).id();
|
||||||
/// }
|
/// }
|
||||||
/// #
|
/// #
|
||||||
@ -111,7 +111,7 @@ type IdCursor = isize;
|
|||||||
///
|
///
|
||||||
/// [learn more]: crate::system::Query#entity-id-access
|
/// [learn more]: crate::system::Query#entity-id-access
|
||||||
/// [`EntityCommands::id`]: crate::system::EntityCommands::id
|
/// [`EntityCommands::id`]: crate::system::EntityCommands::id
|
||||||
/// [`EntityMut::id`]: crate::world::EntityMut::id
|
/// [`EntityWorldMut::id`]: crate::world::EntityWorldMut::id
|
||||||
/// [`EntityCommands`]: crate::system::EntityCommands
|
/// [`EntityCommands`]: crate::system::EntityCommands
|
||||||
/// [`Query::get`]: crate::system::Query::get
|
/// [`Query::get`]: crate::system::Query::get
|
||||||
/// [`World`]: crate::world::World
|
/// [`World`]: crate::world::World
|
||||||
|
|||||||
@ -52,7 +52,7 @@ pub mod prelude {
|
|||||||
Commands, Deferred, In, IntoSystem, Local, NonSend, NonSendMut, ParallelCommands,
|
Commands, Deferred, In, IntoSystem, Local, NonSend, NonSendMut, ParallelCommands,
|
||||||
ParamSet, Query, ReadOnlySystem, Res, ResMut, Resource, System, SystemParamFunction,
|
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,
|
reads_and_writes: FixedBitSet,
|
||||||
/// The exclusively-accessed elements.
|
/// The exclusively-accessed elements.
|
||||||
writes: FixedBitSet,
|
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).
|
/// This field is a performance optimization for `&World` (also harder to mess up for soundness).
|
||||||
reads_all: bool,
|
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>,
|
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("writes", &FormattedBitSet::<T>::new(&self.writes))
|
||||||
.field("reads_all", &self.reads_all)
|
.field("reads_all", &self.reads_all)
|
||||||
|
.field("writes_all", &self.writes_all)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,6 +87,7 @@ impl<T: SparseSetIndex> Access<T> {
|
|||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
reads_all: false,
|
reads_all: false,
|
||||||
|
writes_all: false,
|
||||||
reads_and_writes: FixedBitSet::new(),
|
reads_and_writes: FixedBitSet::new(),
|
||||||
writes: FixedBitSet::new(),
|
writes: FixedBitSet::new(),
|
||||||
marker: PhantomData,
|
marker: PhantomData,
|
||||||
@ -116,14 +121,19 @@ impl<T: SparseSetIndex> Access<T> {
|
|||||||
self.reads_all || self.reads_and_writes.contains(index.sparse_set_index())
|
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`.
|
/// Returns `true` if this can exclusively access the element given by `index`.
|
||||||
pub fn has_write(&self, index: T) -> bool {
|
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.
|
/// Returns `true` if this accesses anything mutably.
|
||||||
pub fn has_any_write(&self) -> bool {
|
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`).
|
/// 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;
|
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`).
|
/// Returns `true` if this has access to all indexed elements (i.e. `&World`).
|
||||||
pub fn has_read_all(&self) -> bool {
|
pub fn has_read_all(&self) -> bool {
|
||||||
self.reads_all
|
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.
|
/// Removes all accesses.
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.reads_all = false;
|
self.reads_all = false;
|
||||||
|
self.writes_all = false;
|
||||||
self.reads_and_writes.clear();
|
self.reads_and_writes.clear();
|
||||||
self.writes.clear();
|
self.writes.clear();
|
||||||
}
|
}
|
||||||
@ -146,6 +168,7 @@ impl<T: SparseSetIndex> Access<T> {
|
|||||||
/// Adds all access from `other`.
|
/// Adds all access from `other`.
|
||||||
pub fn extend(&mut self, other: &Access<T>) {
|
pub fn extend(&mut self, other: &Access<T>) {
|
||||||
self.reads_all = self.reads_all || other.reads_all;
|
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.reads_and_writes.union_with(&other.reads_and_writes);
|
||||||
self.writes.union_with(&other.writes);
|
self.writes.union_with(&other.writes);
|
||||||
}
|
}
|
||||||
@ -155,13 +178,20 @@ impl<T: SparseSetIndex> Access<T> {
|
|||||||
/// [`Access`] instances are incompatible if one can write
|
/// [`Access`] instances are incompatible if one can write
|
||||||
/// an element that the other can read or write.
|
/// an element that the other can read or write.
|
||||||
pub fn is_compatible(&self, other: &Access<T>) -> bool {
|
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 {
|
if self.reads_all {
|
||||||
return other.writes.count_ones(..) == 0;
|
return !other.has_any_write();
|
||||||
}
|
}
|
||||||
|
|
||||||
if other.reads_all {
|
if other.reads_all {
|
||||||
return self.writes.count_ones(..) == 0;
|
return !self.has_any_write();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.writes.is_disjoint(&other.reads_and_writes)
|
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> {
|
pub fn get_conflicts(&self, other: &Access<T>) -> Vec<T> {
|
||||||
let mut conflicts = FixedBitSet::default();
|
let mut conflicts = FixedBitSet::default();
|
||||||
if self.reads_all {
|
if self.reads_all {
|
||||||
|
// QUESTION: How to handle `other.writes_all`?
|
||||||
conflicts.extend(other.writes.ones());
|
conflicts.extend(other.writes.ones());
|
||||||
}
|
}
|
||||||
|
|
||||||
if other.reads_all {
|
if other.reads_all {
|
||||||
|
// QUESTION: How to handle `self.writes_all`.
|
||||||
conflicts.extend(self.writes.ones());
|
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.writes.intersection(&other.reads_and_writes));
|
||||||
conflicts.extend(self.reads_and_writes.intersection(&other.writes));
|
conflicts.extend(self.reads_and_writes.intersection(&other.writes));
|
||||||
conflicts
|
conflicts
|
||||||
@ -377,6 +418,11 @@ impl<T: SparseSetIndex> FilteredAccess<T> {
|
|||||||
pub fn read_all(&mut self) {
|
pub fn read_all(&mut self) {
|
||||||
self.access.read_all();
|
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)]
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
|
|||||||
@ -5,7 +5,7 @@ use crate::{
|
|||||||
entity::Entity,
|
entity::Entity,
|
||||||
query::{Access, DebugCheckedUnwrap, FilteredAccess},
|
query::{Access, DebugCheckedUnwrap, FilteredAccess},
|
||||||
storage::{ComponentSparseSet, Table, TableRow},
|
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;
|
pub use bevy_ecs_macros::WorldQuery;
|
||||||
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
|
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
|
||||||
@ -524,8 +524,8 @@ unsafe impl WorldQuery for Entity {
|
|||||||
unsafe impl ReadOnlyWorldQuery for Entity {}
|
unsafe impl ReadOnlyWorldQuery for Entity {}
|
||||||
|
|
||||||
/// SAFETY: `Self` is the same as `Self::ReadOnly`
|
/// SAFETY: `Self` is the same as `Self::ReadOnly`
|
||||||
unsafe impl<'a> WorldQuery for EntityRef<'a> {
|
unsafe impl WorldQuery for EntityRef<'_> {
|
||||||
type Fetch<'w> = &'w World;
|
type Fetch<'w> = UnsafeWorldCell<'w>;
|
||||||
type Item<'w> = EntityRef<'w>;
|
type Item<'w> = EntityRef<'w>;
|
||||||
type ReadOnly = Self;
|
type ReadOnly = Self;
|
||||||
type State = ();
|
type State = ();
|
||||||
@ -544,8 +544,7 @@ unsafe impl<'a> WorldQuery for EntityRef<'a> {
|
|||||||
_last_run: Tick,
|
_last_run: Tick,
|
||||||
_this_run: Tick,
|
_this_run: Tick,
|
||||||
) -> Self::Fetch<'w> {
|
) -> 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]
|
#[inline]
|
||||||
@ -568,7 +567,9 @@ unsafe impl<'a> WorldQuery for EntityRef<'a> {
|
|||||||
_table_row: TableRow,
|
_table_row: TableRow,
|
||||||
) -> Self::Item<'w> {
|
) -> Self::Item<'w> {
|
||||||
// SAFETY: `fetch` must be called with an entity that exists in the world
|
// 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>) {
|
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
|
/// SAFETY: Access is read-only.
|
||||||
unsafe impl<'a> ReadOnlyWorldQuery for EntityRef<'a> {}
|
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)]
|
#[doc(hidden)]
|
||||||
pub struct ReadFetch<'w, T> {
|
pub struct ReadFetch<'w, T> {
|
||||||
|
|||||||
@ -7,7 +7,7 @@ use std::any::TypeId;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
prelude::Bundle,
|
prelude::Bundle,
|
||||||
world::{EntityMut, FromWorld, World},
|
world::{EntityWorldMut, FromWorld, World},
|
||||||
};
|
};
|
||||||
use bevy_reflect::{FromType, Reflect, ReflectRef, TypeRegistry};
|
use bevy_reflect::{FromType, Reflect, ReflectRef, TypeRegistry};
|
||||||
|
|
||||||
@ -28,13 +28,13 @@ pub struct ReflectBundleFns {
|
|||||||
/// Function pointer implementing [`ReflectBundle::from_world()`].
|
/// Function pointer implementing [`ReflectBundle::from_world()`].
|
||||||
pub from_world: fn(&mut World) -> Box<dyn Reflect>,
|
pub from_world: fn(&mut World) -> Box<dyn Reflect>,
|
||||||
/// Function pointer implementing [`ReflectBundle::insert()`].
|
/// Function pointer implementing [`ReflectBundle::insert()`].
|
||||||
pub insert: fn(&mut EntityMut, &dyn Reflect),
|
pub insert: fn(&mut EntityWorldMut, &dyn Reflect),
|
||||||
/// Function pointer implementing [`ReflectBundle::apply()`].
|
/// 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()`].
|
/// 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()`].
|
/// Function pointer implementing [`ReflectBundle::remove()`].
|
||||||
pub remove: fn(&mut EntityMut),
|
pub remove: fn(&mut EntityWorldMut),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReflectBundleFns {
|
impl ReflectBundleFns {
|
||||||
@ -54,8 +54,8 @@ impl ReflectBundle {
|
|||||||
(self.0.from_world)(world)
|
(self.0.from_world)(world)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert a reflected [`Bundle`] into the entity like [`insert()`](crate::world::EntityMut::insert).
|
/// Insert a reflected [`Bundle`] into the entity like [`insert()`](crate::world::EntityWorldMut::insert).
|
||||||
pub fn insert(&self, entity: &mut EntityMut, bundle: &dyn Reflect) {
|
pub fn insert(&self, entity: &mut EntityWorldMut, bundle: &dyn Reflect) {
|
||||||
(self.0.insert)(entity, bundle);
|
(self.0.insert)(entity, bundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,14 +64,19 @@ impl ReflectBundle {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if there is no [`Bundle`] of the given type.
|
/// 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);
|
(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.
|
/// 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(
|
pub fn apply_or_insert(
|
||||||
&self,
|
&self,
|
||||||
entity: &mut EntityMut,
|
entity: &mut EntityWorldMut,
|
||||||
bundle: &dyn Reflect,
|
bundle: &dyn Reflect,
|
||||||
registry: &TypeRegistry,
|
registry: &TypeRegistry,
|
||||||
) {
|
) {
|
||||||
@ -79,7 +84,7 @@ impl ReflectBundle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Removes this [`Bundle`] type from the entity. Does nothing if it doesn't exist.
|
/// 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);
|
(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()) {
|
if let Some(reflect_component) = registry.get_type_data::<ReflectComponent>(field.type_id()) {
|
||||||
reflect_component.apply(entity, field);
|
reflect_component.apply(entity, field);
|
||||||
} else if let Some(reflect_bundle) = registry.get_type_data::<ReflectBundle>(field.type_id()) {
|
} 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>(
|
fn apply_or_insert_field<B: 'static>(
|
||||||
entity: &mut EntityMut,
|
entity: &mut EntityWorldMut,
|
||||||
field: &dyn Reflect,
|
field: &dyn Reflect,
|
||||||
registry: &TypeRegistry,
|
registry: &TypeRegistry,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -25,7 +25,7 @@
|
|||||||
//! implementation of `ReflectComponent`.
|
//! implementation of `ReflectComponent`.
|
||||||
//!
|
//!
|
||||||
//! The `FromType<C>` impl creates a function per field of [`ReflectComponentFns`].
|
//! 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
|
//! 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`
|
//! of using generic ECS methods such as `entity.get::<C>()` to get `&dyn Reflect`
|
||||||
@ -50,7 +50,7 @@ use crate::{
|
|||||||
change_detection::Mut,
|
change_detection::Mut,
|
||||||
component::Component,
|
component::Component,
|
||||||
entity::Entity,
|
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};
|
use bevy_reflect::{FromType, Reflect};
|
||||||
|
|
||||||
@ -86,19 +86,19 @@ pub struct ReflectComponentFns {
|
|||||||
/// Function pointer implementing [`ReflectComponent::from_world()`].
|
/// Function pointer implementing [`ReflectComponent::from_world()`].
|
||||||
pub from_world: fn(&mut World) -> Box<dyn Reflect>,
|
pub from_world: fn(&mut World) -> Box<dyn Reflect>,
|
||||||
/// Function pointer implementing [`ReflectComponent::insert()`].
|
/// Function pointer implementing [`ReflectComponent::insert()`].
|
||||||
pub insert: fn(&mut EntityMut, &dyn Reflect),
|
pub insert: fn(&mut EntityWorldMut, &dyn Reflect),
|
||||||
/// Function pointer implementing [`ReflectComponent::apply()`].
|
/// 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()`].
|
/// 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()`].
|
/// Function pointer implementing [`ReflectComponent::remove()`].
|
||||||
pub remove: fn(&mut EntityMut),
|
pub remove: fn(&mut EntityWorldMut),
|
||||||
/// Function pointer implementing [`ReflectComponent::contains()`].
|
/// Function pointer implementing [`ReflectComponent::contains()`].
|
||||||
pub contains: fn(EntityRef) -> bool,
|
pub contains: fn(EntityRef) -> bool,
|
||||||
/// Function pointer implementing [`ReflectComponent::reflect()`].
|
/// Function pointer implementing [`ReflectComponent::reflect()`].
|
||||||
pub reflect: fn(EntityRef) -> Option<&dyn Reflect>,
|
pub reflect: fn(EntityRef) -> Option<&dyn Reflect>,
|
||||||
/// Function pointer implementing [`ReflectComponent::reflect_mut()`].
|
/// 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()`].
|
/// Function pointer implementing [`ReflectComponent::reflect_unchecked_mut()`].
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
@ -125,8 +125,8 @@ impl ReflectComponent {
|
|||||||
(self.0.from_world)(world)
|
(self.0.from_world)(world)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert a reflected [`Component`] into the entity like [`insert()`](crate::world::EntityMut::insert).
|
/// Insert a reflected [`Component`] into the entity like [`insert()`](crate::world::EntityWorldMut::insert).
|
||||||
pub fn insert(&self, entity: &mut EntityMut, component: &dyn Reflect) {
|
pub fn insert(&self, entity: &mut EntityWorldMut, component: &dyn Reflect) {
|
||||||
(self.0.insert)(entity, component);
|
(self.0.insert)(entity, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,17 +135,17 @@ impl ReflectComponent {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if there is no [`Component`] of the given type.
|
/// 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);
|
(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.
|
/// 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);
|
(self.0.apply_or_insert)(entity, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes this [`Component`] type from the entity. Does nothing if it doesn't exist.
|
/// 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);
|
(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.
|
/// 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)
|
(self.0.reflect_mut)(entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ use crate::{
|
|||||||
self as bevy_ecs,
|
self as bevy_ecs,
|
||||||
bundle::Bundle,
|
bundle::Bundle,
|
||||||
entity::{Entities, Entity},
|
entity::{Entities, Entity},
|
||||||
world::{EntityMut, FromWorld, World},
|
world::{EntityWorldMut, FromWorld, World},
|
||||||
};
|
};
|
||||||
use bevy_ecs_macros::SystemParam;
|
use bevy_ecs_macros::SystemParam;
|
||||||
use bevy_utils::tracing::{error, info};
|
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.
|
/// 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.
|
/// details.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@ -805,12 +805,11 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use bevy_ecs::prelude::*;
|
/// # use bevy_ecs::prelude::*;
|
||||||
/// # use bevy_ecs::world::EntityMut;
|
|
||||||
/// # fn my_system(mut commands: Commands) {
|
/// # fn my_system(mut commands: Commands) {
|
||||||
/// commands
|
/// commands
|
||||||
/// .spawn_empty()
|
/// .spawn_empty()
|
||||||
/// // Closures with this signature implement `EntityCommand`.
|
/// // Closures with this signature implement `EntityCommand`.
|
||||||
/// .add(|entity: EntityMut| {
|
/// .add(|entity: EntityWorldMut| {
|
||||||
/// println!("Executed an EntityCommand for {:?}", entity.id());
|
/// println!("Executed an EntityCommand for {:?}", entity.id());
|
||||||
/// });
|
/// });
|
||||||
/// # }
|
/// # }
|
||||||
@ -849,7 +848,7 @@ where
|
|||||||
|
|
||||||
impl<F> EntityCommand for F
|
impl<F> EntityCommand for F
|
||||||
where
|
where
|
||||||
F: FnOnce(EntityMut) + Send + 'static,
|
F: FnOnce(EntityWorldMut) + Send + 'static,
|
||||||
{
|
{
|
||||||
fn apply(self, id: Entity, world: &mut World) {
|
fn apply(self, id: Entity, world: &mut World) {
|
||||||
self(world.entity_mut(id));
|
self(world.entity_mut(id));
|
||||||
|
|||||||
@ -14,64 +14,54 @@ use std::any::TypeId;
|
|||||||
|
|
||||||
use super::{unsafe_world_cell::UnsafeEntityCell, Ref};
|
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)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct EntityRef<'w> {
|
pub struct EntityRef<'w>(UnsafeEntityCell<'w>);
|
||||||
world: &'w World,
|
|
||||||
entity: Entity,
|
|
||||||
location: EntityLocation,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'w> EntityRef<'w> {
|
impl<'w> EntityRef<'w> {
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
/// - `cell` must have permission to read every component of the entity.
|
||||||
/// - `entity` must be valid for `world`: the generation should match that of the entity at the same index.
|
/// - No mutable accesses to any of the entity's components may exist
|
||||||
/// - `location` must be sourced from `world`'s `Entities` and must exactly match the location for `entity`
|
/// at the same time as the returned [`EntityRef`].
|
||||||
///
|
|
||||||
/// The above is trivially satisfied if `location` was sourced from `world.entities().get(entity)`.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) unsafe fn new(world: &'w World, entity: Entity, location: EntityLocation) -> Self {
|
pub(crate) unsafe fn new(cell: UnsafeEntityCell<'w>) -> Self {
|
||||||
debug_assert!(world.entities().contains(entity));
|
Self(cell)
|
||||||
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,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the [ID](Entity) of the current entity.
|
/// Returns the [ID](Entity) of the current entity.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use = "Omit the .id() call if you do not need to store the `Entity` identifier."]
|
#[must_use = "Omit the .id() call if you do not need to store the `Entity` identifier."]
|
||||||
pub fn id(&self) -> Entity {
|
pub fn id(&self) -> Entity {
|
||||||
self.entity
|
self.0.id()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets metadata indicating the location where the current entity is stored.
|
/// Gets metadata indicating the location where the current entity is stored.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn location(&self) -> EntityLocation {
|
pub fn location(&self) -> EntityLocation {
|
||||||
self.location
|
self.0.location()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the archetype that the current entity belongs to.
|
/// Returns the archetype that the current entity belongs to.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn archetype(&self) -> &Archetype {
|
pub fn archetype(&self) -> &Archetype {
|
||||||
&self.world.archetypes[self.location.archetype_id]
|
self.0.archetype()
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets read-only access to the world that the current entity belongs to.
|
|
||||||
#[inline]
|
|
||||||
pub fn world(&self) -> &'w World {
|
|
||||||
self.world
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the current entity has a component of type `T`.
|
/// Returns `true` if the current entity has a component of type `T`.
|
||||||
@ -96,8 +86,7 @@ impl<'w> EntityRef<'w> {
|
|||||||
/// [`Self::contains_type_id`].
|
/// [`Self::contains_type_id`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn contains_id(&self, component_id: ComponentId) -> bool {
|
pub fn contains_id(&self, component_id: ComponentId) -> bool {
|
||||||
self.as_unsafe_world_cell_readonly()
|
self.0.contains_id(component_id)
|
||||||
.contains_id(component_id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the current entity has a component with the type identified by `type_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`].
|
/// - If you have a [`ComponentId`] instead of a [`TypeId`], consider using [`Self::contains_id`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn contains_type_id(&self, type_id: TypeId) -> bool {
|
pub fn contains_type_id(&self, type_id: TypeId) -> bool {
|
||||||
self.as_unsafe_world_cell_readonly()
|
self.0.contains_type_id(type_id)
|
||||||
.contains_type_id(type_id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets access to the component of type `T` for the current entity.
|
/// 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`.
|
/// Returns `None` if the entity does not have a component of type `T`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get<T: Component>(&self) -> Option<&'w T> {
|
pub fn get<T: Component>(&self) -> Option<&'w T> {
|
||||||
// SAFETY: &self implies shared access for duration of returned value
|
// SAFETY: We have read-only access to all components of this entity.
|
||||||
unsafe { self.as_unsafe_world_cell_readonly().get::<T>() }
|
unsafe { self.0.get::<T>() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets access to the component of type `T` for the current entity,
|
/// 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`.
|
/// Returns `None` if the entity does not have a component of type `T`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_ref<T: Component>(&self) -> Option<Ref<'w, T>> {
|
pub fn get_ref<T: Component>(&self) -> Option<Ref<'w, T>> {
|
||||||
// SAFETY: &self implies shared access for duration of returned value
|
// SAFETY: We have read-only access to all components of this entity.
|
||||||
unsafe { self.as_unsafe_world_cell_readonly().get_ref::<T>() }
|
unsafe { self.0.get_ref::<T>() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves the change ticks for the given component. This can be useful for implementing change
|
/// Retrieves the change ticks for the given component. This can be useful for implementing change
|
||||||
/// detection in custom runtimes.
|
/// detection in custom runtimes.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_change_ticks<T: Component>(&self) -> Option<ComponentTicks> {
|
pub fn get_change_ticks<T: Component>(&self) -> Option<ComponentTicks> {
|
||||||
// SAFETY: &self implies shared access
|
// SAFETY: We have read-only access to all components of this entity.
|
||||||
unsafe { self.as_unsafe_world_cell_readonly().get_change_ticks::<T>() }
|
unsafe { self.0.get_change_ticks::<T>() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves the change ticks for the given [`ComponentId`]. This can be useful for implementing change
|
/// 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.**
|
/// compile time.**
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_change_ticks_by_id(&self, component_id: ComponentId) -> Option<ComponentTicks> {
|
pub fn get_change_ticks_by_id(&self, component_id: ComponentId) -> Option<ComponentTicks> {
|
||||||
// SAFETY: &self implies shared access
|
// SAFETY: We have read-only access to all components of this entity.
|
||||||
unsafe {
|
unsafe { self.0.get_change_ticks_by_id(component_id) }
|
||||||
self.as_unsafe_world_cell_readonly()
|
|
||||||
.get_change_ticks_by_id(component_id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w> EntityRef<'w> {
|
|
||||||
/// Gets the component of the given [`ComponentId`] from the entity.
|
/// Gets the component of the given [`ComponentId`] from the entity.
|
||||||
///
|
///
|
||||||
/// **You should prefer to use the typed API where possible and only
|
/// **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.
|
/// which is only valid while the `'w` borrow of the lifetime is active.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_by_id(&self, component_id: ComponentId) -> Option<Ptr<'w>> {
|
pub fn get_by_id(&self, component_id: ComponentId) -> Option<Ptr<'w>> {
|
||||||
// SAFETY: &self implies shared access for duration of returned value
|
// SAFETY: We have read-only access to all components of this entity.
|
||||||
unsafe { self.as_unsafe_world_cell_readonly().get_by_id(component_id) }
|
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> {
|
impl<'w> From<EntityMut<'w>> for EntityRef<'w> {
|
||||||
fn from(entity_mut: EntityMut<'w>) -> EntityRef<'w> {
|
fn from(value: EntityMut<'w>) -> Self {
|
||||||
// SAFETY: the safety invariants on EntityMut and EntityRef are identical
|
// SAFETY:
|
||||||
// and EntityMut is promised to be valid by construction.
|
// - `EntityMut` gurantees exclusive access to all of the entity's components.
|
||||||
unsafe { EntityRef::new(entity_mut.world, entity_mut.entity, entity_mut.location) }
|
unsafe { EntityRef::new(value.0) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A mutable reference to a particular [`Entity`] and all of its components
|
impl<'a> From<&'a EntityMut<'_>> for EntityRef<'a> {
|
||||||
pub struct EntityMut<'w> {
|
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,
|
world: &'w mut World,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
location: EntityLocation,
|
location: EntityLocation,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w> EntityMut<'w> {
|
impl<'w> EntityWorldMut<'w> {
|
||||||
fn as_unsafe_world_cell_readonly(&self) -> UnsafeEntityCell<'_> {
|
fn as_unsafe_entity_cell_readonly(&self) -> UnsafeEntityCell<'_> {
|
||||||
UnsafeEntityCell::new(
|
UnsafeEntityCell::new(
|
||||||
self.world.as_unsafe_world_cell_readonly(),
|
self.world.as_unsafe_world_cell_readonly(),
|
||||||
self.entity,
|
self.entity,
|
||||||
self.location,
|
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(
|
UnsafeEntityCell::new(
|
||||||
self.world.as_unsafe_world_cell(),
|
self.world.as_unsafe_world_cell(),
|
||||||
self.entity,
|
self.entity,
|
||||||
@ -217,7 +428,7 @@ impl<'w> EntityMut<'w> {
|
|||||||
debug_assert!(world.entities().contains(entity));
|
debug_assert!(world.entities().contains(entity));
|
||||||
debug_assert_eq!(world.entities().get(entity), Some(location));
|
debug_assert_eq!(world.entities().get(entity), Some(location));
|
||||||
|
|
||||||
EntityMut {
|
EntityWorldMut {
|
||||||
world,
|
world,
|
||||||
entity,
|
entity,
|
||||||
location,
|
location,
|
||||||
@ -265,7 +476,7 @@ impl<'w> EntityMut<'w> {
|
|||||||
/// [`Self::contains_type_id`].
|
/// [`Self::contains_type_id`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn contains_id(&self, component_id: ComponentId) -> bool {
|
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)
|
.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`].
|
/// - If you have a [`ComponentId`] instead of a [`TypeId`], consider using [`Self::contains_id`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn contains_type_id(&self, type_id: TypeId) -> bool {
|
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)
|
.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`.
|
/// Returns `None` if the entity does not have a component of type `T`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get<T: Component>(&self) -> Option<&'_ T> {
|
pub fn get<T: Component>(&self) -> Option<&'_ T> {
|
||||||
// SAFETY: &self implies shared access for duration of returned value
|
EntityRef::from(self).get()
|
||||||
unsafe { self.as_unsafe_world_cell_readonly().get::<T>() }
|
}
|
||||||
|
|
||||||
|
/// 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.
|
/// Gets mutable access to the component of type `T` for the current entity.
|
||||||
@ -295,30 +514,54 @@ impl<'w> EntityMut<'w> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_mut<T: Component>(&mut self) -> Option<Mut<'_, T>> {
|
pub fn get_mut<T: Component>(&mut self) -> Option<Mut<'_, T>> {
|
||||||
// SAFETY: &mut self implies exclusive access for duration of returned value
|
// 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
|
/// Retrieves the change ticks for the given component. This can be useful for implementing change
|
||||||
/// detection in custom runtimes.
|
/// detection in custom runtimes.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_change_ticks<T: Component>(&self) -> Option<ComponentTicks> {
|
pub fn get_change_ticks<T: Component>(&self) -> Option<ComponentTicks> {
|
||||||
// SAFETY: &self implies shared access
|
EntityRef::from(self).get_change_ticks::<T>()
|
||||||
unsafe { self.as_unsafe_world_cell_readonly().get_change_ticks::<T>() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves the change ticks for the given [`ComponentId`]. This can be useful for implementing change
|
/// Retrieves the change ticks for the given [`ComponentId`]. This can be useful for implementing change
|
||||||
/// detection in custom runtimes.
|
/// 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
|
/// use this in cases where the actual component types are not known at
|
||||||
/// compile time.**
|
/// compile time.**
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_change_ticks_by_id(&self, component_id: ComponentId) -> Option<ComponentTicks> {
|
pub fn get_change_ticks_by_id(&self, component_id: ComponentId) -> Option<ComponentTicks> {
|
||||||
// SAFETY: &self implies shared access
|
EntityRef::from(self).get_change_ticks_by_id(component_id)
|
||||||
unsafe {
|
|
||||||
self.as_unsafe_world_cell_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 [`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.
|
/// 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.
|
/// 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
|
/// # 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`]
|
/// - [`OwningPtr`] must be a valid reference to the type represented by [`ComponentId`]
|
||||||
pub unsafe fn insert_by_id(
|
pub unsafe fn insert_by_id(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -391,13 +634,13 @@ impl<'w> EntityMut<'w> {
|
|||||||
///
|
///
|
||||||
/// This will overwrite any previous value(s) of the same component type.
|
/// 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.
|
||||||
/// If your [`Bundle`] only has one component, use the cached API [`EntityMut::insert_by_id`].
|
/// 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.
|
/// If possible, pass a sorted slice of `ComponentId` to maximize caching potential.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # 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`]
|
/// - 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>>>(
|
pub unsafe fn insert_by_ids<'a, I: Iterator<Item = OwningPtr<'a>>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -719,27 +962,27 @@ impl<'w> EntityMut<'w> {
|
|||||||
self.world
|
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
|
/// # Safety
|
||||||
/// Caller must not modify the world in a way that changes the current entity's location
|
/// 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()`
|
/// 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]
|
#[inline]
|
||||||
pub unsafe fn world_mut(&mut self) -> &mut World {
|
pub unsafe fn world_mut(&mut self) -> &mut World {
|
||||||
self.world
|
self.world
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns this `EntityMut`'s [`World`], consuming itself.
|
/// Returns this entity's [`World`], consuming itself.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn into_world_mut(self) -> &'w mut World {
|
pub fn into_world_mut(self) -> &'w mut World {
|
||||||
self.world
|
self.world
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gives mutable access to this `EntityMut`'s [`World`] in a temporary scope.
|
/// Gives mutable access to this entity's [`World`] in a temporary scope.
|
||||||
/// This is a safe alternative to using [`Self::world_mut`].
|
/// This is a safe alternative to using [`EntityWorldMut::world_mut`].
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@ -757,14 +1000,14 @@ impl<'w> EntityMut<'w> {
|
|||||||
/// let mut r = world.resource_mut::<R>();
|
/// let mut r = world.resource_mut::<R>();
|
||||||
/// r.0 += 1;
|
/// 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
|
/// *r
|
||||||
/// });
|
/// });
|
||||||
/// # assert_eq!(new_r.0, 1);
|
/// # assert_eq!(new_r.0, 1);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn world_scope<U>(&mut self, f: impl FnOnce(&mut World) -> U) -> U {
|
pub fn world_scope<U>(&mut self, f: impl FnOnce(&mut World) -> U) -> U {
|
||||||
struct Guard<'w, 'a> {
|
struct Guard<'w, 'a> {
|
||||||
entity_mut: &'a mut EntityMut<'w>,
|
entity_mut: &'a mut EntityWorldMut<'w>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Guard<'_, '_> {
|
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
|
/// Updates the internal entity location to match the current location in the internal
|
||||||
/// [`World`].
|
/// [`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.
|
/// which enables the location to change.
|
||||||
pub fn update_location(&mut self) {
|
pub fn update_location(&mut self) {
|
||||||
self.location = self.world.entities().get(self.entity).unwrap();
|
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.
|
/// Inserts a dynamic [`Bundle`] into the entity.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
@ -1027,9 +1236,7 @@ mod tests {
|
|||||||
use bevy_ptr::OwningPtr;
|
use bevy_ptr::OwningPtr;
|
||||||
use std::panic::AssertUnwindSafe;
|
use std::panic::AssertUnwindSafe;
|
||||||
|
|
||||||
use crate as bevy_ecs;
|
use crate::{self as bevy_ecs, component::ComponentId, prelude::*, system::assert_is_system};
|
||||||
use crate::component::ComponentId;
|
|
||||||
use crate::prelude::*; // for the `#[derive(Component)]`
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sorted_remove() {
|
fn sorted_remove() {
|
||||||
@ -1090,7 +1297,7 @@ mod tests {
|
|||||||
{
|
{
|
||||||
test_component.set_changed();
|
test_component.set_changed();
|
||||||
let test_component =
|
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>() };
|
unsafe { test_component.into_inner().deref_mut::<TestComponent>() };
|
||||||
test_component.0 = 43;
|
test_component.0 = 43;
|
||||||
}
|
}
|
||||||
@ -1133,7 +1340,7 @@ mod tests {
|
|||||||
let id = entity.id();
|
let id = entity.id();
|
||||||
let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
|
let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
|
||||||
entity.world_scope(|w| {
|
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.
|
// This will get updated at the end of the scope.
|
||||||
w.entity_mut(id).insert(TestComponent(0));
|
w.entity_mut(id).insert(TestComponent(0));
|
||||||
|
|
||||||
@ -1369,4 +1576,113 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(dynamic_components, static_components);
|
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;
|
mod world_cell;
|
||||||
|
|
||||||
pub use crate::change_detection::{Mut, Ref, CHECK_TICK_THRESHOLD};
|
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 spawn_batch::*;
|
||||||
pub use world_cell::*;
|
pub use world_cell::*;
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ use crate::{
|
|||||||
component::{Component, ComponentDescriptor, ComponentId, ComponentInfo, Components, Tick},
|
component::{Component, ComponentDescriptor, ComponentId, ComponentInfo, Components, Tick},
|
||||||
entity::{AllocAtWithoutReplacement, Entities, Entity, EntityLocation},
|
entity::{AllocAtWithoutReplacement, Entities, Entity, EntityLocation},
|
||||||
event::{Event, Events},
|
event::{Event, Events},
|
||||||
query::{DebugCheckedUnwrap, QueryState, ReadOnlyWorldQuery, WorldQuery},
|
query::{DebugCheckedUnwrap, QueryEntityError, QueryState, ReadOnlyWorldQuery, WorldQuery},
|
||||||
removal_detection::RemovedComponentEvents,
|
removal_detection::RemovedComponentEvents,
|
||||||
schedule::{Schedule, ScheduleLabel, Schedules},
|
schedule::{Schedule, ScheduleLabel, Schedules},
|
||||||
storage::{ResourceData, Storages},
|
storage::{ResourceData, Storages},
|
||||||
@ -30,13 +30,14 @@ use bevy_utils::tracing::warn;
|
|||||||
use std::{
|
use std::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
fmt,
|
fmt,
|
||||||
|
mem::MaybeUninit,
|
||||||
sync::atomic::{AtomicU32, Ordering},
|
sync::atomic::{AtomicU32, Ordering},
|
||||||
};
|
};
|
||||||
mod identifier;
|
mod identifier;
|
||||||
|
|
||||||
pub use identifier::WorldId;
|
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,
|
/// Stores and exposes operations on [entities](Entity), [components](Component), resources,
|
||||||
/// and their associated metadata.
|
/// 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
|
/// 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.
|
/// to check for entity existence instead of implicitly panic-ing.
|
||||||
///
|
///
|
||||||
@ -277,7 +278,7 @@ impl World {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn entity_mut(&mut self, entity: Entity) -> EntityMut {
|
pub fn entity_mut(&mut self, entity: Entity) -> EntityWorldMut {
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[cold]
|
#[cold]
|
||||||
#[track_caller]
|
#[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).
|
/// Returns the components of an [`Entity`](crate::entity::Entity) through [`ComponentInfo`](crate::component::ComponentInfo).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn inspect_entity(&self, entity: Entity) -> Vec<&ComponentInfo> {
|
pub fn inspect_entity(&self, entity: Entity) -> Vec<&ComponentInfo> {
|
||||||
@ -315,7 +401,7 @@ impl World {
|
|||||||
.collect()
|
.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.
|
/// This will return [`None`] if the `entity` exists with a different generation.
|
||||||
///
|
///
|
||||||
/// # Note
|
/// # 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
|
/// 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).
|
/// scheme worked out to share an ID space (which doesn't happen by default).
|
||||||
#[inline]
|
#[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();
|
self.flush();
|
||||||
match self.entities.alloc_at_without_replacement(entity) {
|
match self.entities.alloc_at_without_replacement(entity) {
|
||||||
AllocAtWithoutReplacement::Exists(location) => {
|
AllocAtWithoutReplacement::Exists(location) => {
|
||||||
// SAFETY: `entity` exists and `location` is that entity's 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 => {
|
AllocAtWithoutReplacement::DidNotExist => {
|
||||||
// SAFETY: entity was just allocated
|
// SAFETY: entity was just allocated
|
||||||
@ -339,8 +425,8 @@ impl World {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves an [`EntityRef`] that exposes read-only operations for the given `entity`.
|
/// 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
|
/// Returns [`None`] if the `entity` does not exist.
|
||||||
/// to unwrap the [`EntityRef`] yourself.
|
/// Instead of unwrapping the value returned from this function, prefer [`World::entity`].
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use bevy_ecs::{component::Component, world::World};
|
/// use bevy_ecs::{component::Component, world::World};
|
||||||
@ -362,10 +448,48 @@ impl World {
|
|||||||
let location = self.entities.get(entity)?;
|
let location = self.entities.get(entity)?;
|
||||||
// SAFETY: if the Entity is invalid, the function returns early.
|
// SAFETY: if the Entity is invalid, the function returns early.
|
||||||
// Additionally, Entities::get(entity) returns the correct EntityLocation if the entity exists.
|
// 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)
|
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.
|
/// Returns an [`Entity`] iterator of current entities.
|
||||||
///
|
///
|
||||||
/// This is useful in contexts where you only have read-only access to the [`World`].
|
/// 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(),
|
table_row: archetype_entity.table_row(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// SAFETY: entity exists and location accurately specifies the archetype where the entity is stored
|
// SAFETY: entity exists and location accurately specifies the archetype where the entity is stored.
|
||||||
unsafe { EntityRef::new(self, entity, location) }
|
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 a mutable iterator over all entities in the `World`.
|
||||||
/// Returns [`None`] if the `entity` does not exist. Use [`World::entity_mut`] if you don't want
|
pub fn iter_entities_mut(&mut self) -> impl Iterator<Item = EntityMut<'_>> + '_ {
|
||||||
/// to unwrap the [`EntityMut`] yourself.
|
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};
|
/// use bevy_ecs::{component::Component, world::World};
|
||||||
@ -411,13 +567,78 @@ impl World {
|
|||||||
/// position.x = 1.0;
|
/// position.x = 1.0;
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[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)?;
|
let location = self.entities.get(entity)?;
|
||||||
// SAFETY: `entity` exists and `location` is that entity's 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) })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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.
|
/// to add components to the entity or retrieve its id.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
@ -442,7 +663,7 @@ impl World {
|
|||||||
/// let position = world.entity(entity).get::<Position>().unwrap();
|
/// let position = world.entity(entity).get::<Position>().unwrap();
|
||||||
/// assert_eq!(position.x, 0.0);
|
/// assert_eq!(position.x, 0.0);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn spawn_empty(&mut self) -> EntityMut {
|
pub fn spawn_empty(&mut self) -> EntityWorldMut {
|
||||||
self.flush();
|
self.flush();
|
||||||
let entity = self.entities.alloc();
|
let entity = self.entities.alloc();
|
||||||
// SAFETY: entity was just allocated
|
// SAFETY: entity was just allocated
|
||||||
@ -450,7 +671,7 @@ impl World {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Spawns a new [`Entity`] with a given [`Bundle`] of [components](`Component`) and returns
|
/// 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.
|
/// retrieve its id.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
@ -508,7 +729,7 @@ impl World {
|
|||||||
/// let position = world.entity(entity).get::<Position>().unwrap();
|
/// let position = world.entity(entity).get::<Position>().unwrap();
|
||||||
/// assert_eq!(position.x, 2.0);
|
/// 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();
|
self.flush();
|
||||||
let change_tick = self.change_tick();
|
let change_tick = self.change_tick();
|
||||||
let entity = self.entities.alloc();
|
let entity = self.entities.alloc();
|
||||||
@ -529,12 +750,12 @@ impl World {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// SAFETY: entity and location are valid, as they were just created above
|
// 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
|
/// # Safety
|
||||||
/// must be called on an entity that was just allocated
|
/// 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();
|
let archetype = self.archetypes.empty_mut();
|
||||||
// PERF: consider avoiding allocating entities in the empty archetype unless needed
|
// PERF: consider avoiding allocating entities in the empty archetype unless needed
|
||||||
let table_row = self.storages.tables[archetype.table_id()].allocate(entity);
|
let table_row = self.storages.tables[archetype.table_id()].allocate(entity);
|
||||||
@ -543,7 +764,7 @@ impl World {
|
|||||||
let location = archetype.allocate(entity, table_row);
|
let location = archetype.allocate(entity, table_row);
|
||||||
// SAFETY: entity index was just allocated
|
// SAFETY: entity index was just allocated
|
||||||
self.entities.set(entity.index(), location);
|
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]
|
/// 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);
|
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]
|
#[test]
|
||||||
fn spawn_empty_bundle() {
|
fn spawn_empty_bundle() {
|
||||||
let mut world = World::new();
|
let mut world = World::new();
|
||||||
|
|||||||
@ -4,7 +4,7 @@ use bevy_ecs::{
|
|||||||
entity::Entity,
|
entity::Entity,
|
||||||
prelude::Events,
|
prelude::Events,
|
||||||
system::{Command, Commands, EntityCommands},
|
system::{Command, Commands, EntityCommands},
|
||||||
world::{EntityMut, World},
|
world::{EntityWorldMut, World},
|
||||||
};
|
};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
@ -460,7 +460,7 @@ pub struct WorldChildBuilder<'w> {
|
|||||||
impl<'w> WorldChildBuilder<'w> {
|
impl<'w> WorldChildBuilder<'w> {
|
||||||
/// Spawns an entity with the given bundle and inserts it into the parent entity's [`Children`].
|
/// Spawns an entity with the given bundle and inserts it into the parent entity's [`Children`].
|
||||||
/// Also adds [`Parent`] component to the created entity.
|
/// 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();
|
let entity = self.world.spawn((bundle, Parent(self.parent))).id();
|
||||||
push_child_unchecked(self.world, self.parent, entity);
|
push_child_unchecked(self.world, self.parent, entity);
|
||||||
push_events(
|
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`].
|
/// Spawns an [`Entity`] with no components and inserts it into the parent entity's [`Children`].
|
||||||
/// Also adds [`Parent`] component to the created entity.
|
/// 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();
|
let entity = self.world.spawn(Parent(self.parent)).id();
|
||||||
push_child_unchecked(self.world, self.parent, entity);
|
push_child_unchecked(self.world, self.parent, entity);
|
||||||
push_events(
|
push_events(
|
||||||
@ -554,7 +554,7 @@ pub trait BuildWorldChildren {
|
|||||||
fn remove_parent(&mut self) -> &mut Self;
|
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 {
|
fn with_children(&mut self, spawn_children: impl FnOnce(&mut WorldChildBuilder)) -> &mut Self {
|
||||||
let parent = self.id();
|
let parent = self.id();
|
||||||
self.world_scope(|world| {
|
self.world_scope(|world| {
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use crate::components::{Children, Parent};
|
|||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
system::{Command, EntityCommands},
|
system::{Command, EntityCommands},
|
||||||
world::{EntityMut, World},
|
world::{EntityWorldMut, World},
|
||||||
};
|
};
|
||||||
use bevy_utils::tracing::debug;
|
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.
|
/// Despawns the provided entity and its children.
|
||||||
fn despawn_recursive(self) {
|
fn despawn_recursive(self) {
|
||||||
let entity = self.id();
|
let entity = self.id();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user