
# Objective Allow `EntityCommand` implementors to delegate to other entity commands easily: ```rs impl EntityCommand for Foo { fn apply(self, mut entity: EntityWorldMut) { entity.reborrow_scope(|e| StepOne.apply(e)); entity.reborrow_scope(|e| StepTwo.apply(e)); } } ```
6141 lines
215 KiB
Rust
6141 lines
215 KiB
Rust
use crate::{
|
|
archetype::{Archetype, ArchetypeId},
|
|
bundle::{
|
|
Bundle, BundleEffect, BundleFromComponents, BundleInserter, BundleRemover, DynamicBundle,
|
|
InsertMode,
|
|
},
|
|
change_detection::{MaybeLocation, MutUntyped},
|
|
component::{
|
|
Component, ComponentId, ComponentTicks, Components, ComponentsRegistrator, Mutable,
|
|
StorageType,
|
|
},
|
|
entity::{
|
|
ContainsEntity, Entity, EntityCloner, EntityClonerBuilder, EntityEquivalent, EntityLocation,
|
|
},
|
|
event::Event,
|
|
observer::Observer,
|
|
query::{Access, DebugCheckedUnwrap, ReadOnlyQueryData},
|
|
relationship::RelationshipHookMode,
|
|
resource::Resource,
|
|
system::IntoObserverSystem,
|
|
world::{
|
|
error::EntityComponentError, unsafe_world_cell::UnsafeEntityCell, Mut, Ref, World,
|
|
ON_DESPAWN, ON_REMOVE, ON_REPLACE,
|
|
},
|
|
};
|
|
use alloc::vec::Vec;
|
|
use bevy_platform::collections::{HashMap, HashSet};
|
|
use bevy_ptr::{OwningPtr, Ptr};
|
|
use core::{
|
|
any::TypeId,
|
|
cmp::Ordering,
|
|
hash::{Hash, Hasher},
|
|
marker::PhantomData,
|
|
mem::MaybeUninit,
|
|
};
|
|
use thiserror::Error;
|
|
|
|
/// A read-only reference to a particular [`Entity`] and all of its components.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// Read-only access disjoint with mutable access.
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// # #[derive(Component)] pub struct A;
|
|
/// # #[derive(Component)] pub struct B;
|
|
/// fn disjoint_system(
|
|
/// query1: Query<&mut A>,
|
|
/// query2: Query<EntityRef, Without<A>>,
|
|
/// ) {
|
|
/// // ...
|
|
/// }
|
|
/// # bevy_ecs::system::assert_is_system(disjoint_system);
|
|
/// ```
|
|
#[derive(Copy, Clone)]
|
|
pub struct EntityRef<'w> {
|
|
cell: UnsafeEntityCell<'w>,
|
|
}
|
|
|
|
impl<'w> EntityRef<'w> {
|
|
/// # Safety
|
|
/// - `cell` must have permission to read every component of the entity.
|
|
/// - No mutable accesses to any of the entity's components may exist
|
|
/// at the same time as the returned [`EntityRef`].
|
|
#[inline]
|
|
pub(crate) unsafe fn new(cell: UnsafeEntityCell<'w>) -> Self {
|
|
Self { cell }
|
|
}
|
|
|
|
/// Returns the [ID](Entity) of the current entity.
|
|
#[inline]
|
|
#[must_use = "Omit the .id() call if you do not need to store the `Entity` identifier."]
|
|
pub fn id(&self) -> Entity {
|
|
self.cell.id()
|
|
}
|
|
|
|
/// Gets metadata indicating the location where the current entity is stored.
|
|
#[inline]
|
|
pub fn location(&self) -> EntityLocation {
|
|
self.cell.location()
|
|
}
|
|
|
|
/// Returns the archetype that the current entity belongs to.
|
|
#[inline]
|
|
pub fn archetype(&self) -> &Archetype {
|
|
self.cell.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.cell.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.cell.contains_type_id(type_id)
|
|
}
|
|
|
|
/// Gets access to the component of type `T` for the current entity.
|
|
/// Returns `None` if the entity does not have a component of type `T`.
|
|
#[inline]
|
|
pub fn get<T: Component>(&self) -> Option<&'w T> {
|
|
// SAFETY: We have read-only access to all components of this entity.
|
|
unsafe { self.cell.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<'w, T>> {
|
|
// SAFETY: We have read-only access to all components of this entity.
|
|
unsafe { self.cell.get_ref::<T>() }
|
|
}
|
|
|
|
/// Retrieves the change ticks for the given component. This can be useful for implementing change
|
|
/// detection in custom runtimes.
|
|
#[inline]
|
|
pub fn get_change_ticks<T: Component>(&self) -> Option<ComponentTicks> {
|
|
// SAFETY: We have read-only access to all components of this entity.
|
|
unsafe { self.cell.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 [`EntityRef::get_change_ticks`] where possible and only
|
|
/// use this in cases where the actual component types are not known at
|
|
/// compile time.**
|
|
#[inline]
|
|
pub fn get_change_ticks_by_id(&self, component_id: ComponentId) -> Option<ComponentTicks> {
|
|
// SAFETY: We have read-only access to all components of this entity.
|
|
unsafe { self.cell.get_change_ticks_by_id(component_id) }
|
|
}
|
|
|
|
/// Returns [untyped read-only reference(s)](Ptr) to component(s) for the
|
|
/// current entity, based on the given [`ComponentId`]s.
|
|
///
|
|
/// **You should prefer to use the typed API [`EntityRef::get`] where
|
|
/// possible and only use this in cases where the actual component types
|
|
/// are not known at compile time.**
|
|
///
|
|
/// Unlike [`EntityRef::get`], this returns untyped reference(s) to
|
|
/// component(s), and it's the job of the caller to ensure the correct
|
|
/// type(s) are dereferenced (if necessary).
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// Returns [`EntityComponentError::MissingComponent`] if the entity does
|
|
/// not have a component.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ## Single [`ComponentId`]
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// #
|
|
/// # #[derive(Component, PartialEq, Debug)]
|
|
/// # pub struct Foo(i32);
|
|
/// # let mut world = World::new();
|
|
/// let entity = world.spawn(Foo(42)).id();
|
|
///
|
|
/// // Grab the component ID for `Foo` in whatever way you like.
|
|
/// let component_id = world.register_component::<Foo>();
|
|
///
|
|
/// // Then, get the component by ID.
|
|
/// let ptr = world.entity(entity).get_by_id(component_id);
|
|
/// # assert_eq!(unsafe { ptr.unwrap().deref::<Foo>() }, &Foo(42));
|
|
/// ```
|
|
///
|
|
/// ## Array of [`ComponentId`]s
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// #
|
|
/// # #[derive(Component, PartialEq, Debug)]
|
|
/// # pub struct X(i32);
|
|
/// # #[derive(Component, PartialEq, Debug)]
|
|
/// # pub struct Y(i32);
|
|
/// # let mut world = World::new();
|
|
/// let entity = world.spawn((X(42), Y(10))).id();
|
|
///
|
|
/// // Grab the component IDs for `X` and `Y` in whatever way you like.
|
|
/// let x_id = world.register_component::<X>();
|
|
/// let y_id = world.register_component::<Y>();
|
|
///
|
|
/// // Then, get the components by ID. You'll receive a same-sized array.
|
|
/// let Ok([x_ptr, y_ptr]) = world.entity(entity).get_by_id([x_id, y_id]) else {
|
|
/// // Up to you to handle if a component is missing from the entity.
|
|
/// # unreachable!();
|
|
/// };
|
|
/// # assert_eq!((unsafe { x_ptr.deref::<X>() }, unsafe { y_ptr.deref::<Y>() }), (&X(42), &Y(10)));
|
|
/// ```
|
|
///
|
|
/// ## Slice of [`ComponentId`]s
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::{prelude::*, component::ComponentId};
|
|
/// #
|
|
/// # #[derive(Component, PartialEq, Debug)]
|
|
/// # pub struct X(i32);
|
|
/// # #[derive(Component, PartialEq, Debug)]
|
|
/// # pub struct Y(i32);
|
|
/// # let mut world = World::new();
|
|
/// let entity = world.spawn((X(42), Y(10))).id();
|
|
///
|
|
/// // Grab the component IDs for `X` and `Y` in whatever way you like.
|
|
/// let x_id = world.register_component::<X>();
|
|
/// let y_id = world.register_component::<Y>();
|
|
///
|
|
/// // Then, get the components by ID. You'll receive a vec of ptrs.
|
|
/// let ptrs = world.entity(entity).get_by_id(&[x_id, y_id] as &[ComponentId]);
|
|
/// # let ptrs = ptrs.unwrap();
|
|
/// # assert_eq!((unsafe { ptrs[0].deref::<X>() }, unsafe { ptrs[1].deref::<Y>() }), (&X(42), &Y(10)));
|
|
/// ```
|
|
///
|
|
/// ## [`HashSet`] of [`ComponentId`]s
|
|
///
|
|
/// ```
|
|
/// # use bevy_platform::collections::HashSet;
|
|
/// # use bevy_ecs::{prelude::*, component::ComponentId};
|
|
/// #
|
|
/// # #[derive(Component, PartialEq, Debug)]
|
|
/// # pub struct X(i32);
|
|
/// # #[derive(Component, PartialEq, Debug)]
|
|
/// # pub struct Y(i32);
|
|
/// # let mut world = World::new();
|
|
/// let entity = world.spawn((X(42), Y(10))).id();
|
|
///
|
|
/// // Grab the component IDs for `X` and `Y` in whatever way you like.
|
|
/// let x_id = world.register_component::<X>();
|
|
/// let y_id = world.register_component::<Y>();
|
|
///
|
|
/// // Then, get the components by ID. You'll receive a vec of ptrs.
|
|
/// let ptrs = world.entity(entity).get_by_id(&HashSet::from_iter([x_id, y_id]));
|
|
/// # let ptrs = ptrs.unwrap();
|
|
/// # assert_eq!((unsafe { ptrs[&x_id].deref::<X>() }, unsafe { ptrs[&y_id].deref::<Y>() }), (&X(42), &Y(10)));
|
|
/// ```
|
|
#[inline]
|
|
pub fn get_by_id<F: DynamicComponentFetch>(
|
|
&self,
|
|
component_ids: F,
|
|
) -> Result<F::Ref<'w>, EntityComponentError> {
|
|
// SAFETY: We have read-only access to all components of this entity.
|
|
unsafe { component_ids.fetch_ref(self.cell) }
|
|
}
|
|
|
|
/// Returns read-only components for the current entity that match the query `Q`.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity does not have the components required by the query `Q`.
|
|
pub fn components<Q: ReadOnlyQueryData>(&self) -> Q::Item<'w> {
|
|
self.get_components::<Q>()
|
|
.expect("Query does not match the current entity")
|
|
}
|
|
|
|
/// Returns read-only components for the current entity that match the query `Q`,
|
|
/// or `None` if the entity does not have the components required by the query `Q`.
|
|
pub fn get_components<Q: ReadOnlyQueryData>(&self) -> Option<Q::Item<'w>> {
|
|
// SAFETY: We have read-only access to all components of this entity.
|
|
unsafe { self.cell.get_components::<Q>() }
|
|
}
|
|
|
|
/// Returns the source code location from which this entity has been spawned.
|
|
pub fn spawned_by(&self) -> MaybeLocation {
|
|
self.cell.spawned_by()
|
|
}
|
|
}
|
|
|
|
impl<'w> From<EntityWorldMut<'w>> for EntityRef<'w> {
|
|
fn from(entity: EntityWorldMut<'w>) -> EntityRef<'w> {
|
|
// SAFETY:
|
|
// - `EntityWorldMut` guarantees exclusive access to the entire world.
|
|
unsafe { EntityRef::new(entity.into_unsafe_entity_cell()) }
|
|
}
|
|
}
|
|
|
|
impl<'a> From<&'a EntityWorldMut<'_>> for EntityRef<'a> {
|
|
fn from(entity: &'a EntityWorldMut<'_>) -> Self {
|
|
// SAFETY:
|
|
// - `EntityWorldMut` guarantees exclusive access to the entire world.
|
|
// - `&entity` ensures no mutable accesses are active.
|
|
unsafe { EntityRef::new(entity.as_unsafe_entity_cell_readonly()) }
|
|
}
|
|
}
|
|
|
|
impl<'w> From<EntityMut<'w>> for EntityRef<'w> {
|
|
fn from(entity: EntityMut<'w>) -> Self {
|
|
// SAFETY:
|
|
// - `EntityMut` guarantees exclusive access to all of the entity's components.
|
|
unsafe { EntityRef::new(entity.cell) }
|
|
}
|
|
}
|
|
|
|
impl<'a> From<&'a EntityMut<'_>> for EntityRef<'a> {
|
|
fn from(entity: &'a EntityMut<'_>) -> Self {
|
|
// SAFETY:
|
|
// - `EntityMut` guarantees exclusive access to all of the entity's components.
|
|
// - `&entity` ensures there are no mutable accesses.
|
|
unsafe { EntityRef::new(entity.cell) }
|
|
}
|
|
}
|
|
|
|
impl<'a> TryFrom<FilteredEntityRef<'a>> for EntityRef<'a> {
|
|
type Error = TryFromFilteredError;
|
|
|
|
fn try_from(entity: FilteredEntityRef<'a>) -> Result<Self, Self::Error> {
|
|
if !entity.access.has_read_all() {
|
|
Err(TryFromFilteredError::MissingReadAllAccess)
|
|
} else {
|
|
// SAFETY: check above guarantees read-only access to all components of the entity.
|
|
Ok(unsafe { EntityRef::new(entity.entity) })
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> TryFrom<&'a FilteredEntityRef<'_>> for EntityRef<'a> {
|
|
type Error = TryFromFilteredError;
|
|
|
|
fn try_from(entity: &'a FilteredEntityRef<'_>) -> Result<Self, Self::Error> {
|
|
if !entity.access.has_read_all() {
|
|
Err(TryFromFilteredError::MissingReadAllAccess)
|
|
} else {
|
|
// SAFETY: check above guarantees read-only access to all components of the entity.
|
|
Ok(unsafe { EntityRef::new(entity.entity) })
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> TryFrom<FilteredEntityMut<'a>> for EntityRef<'a> {
|
|
type Error = TryFromFilteredError;
|
|
|
|
fn try_from(entity: FilteredEntityMut<'a>) -> Result<Self, Self::Error> {
|
|
if !entity.access.has_read_all() {
|
|
Err(TryFromFilteredError::MissingReadAllAccess)
|
|
} else {
|
|
// SAFETY: check above guarantees read-only access to all components of the entity.
|
|
Ok(unsafe { EntityRef::new(entity.entity) })
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> TryFrom<&'a FilteredEntityMut<'_>> for EntityRef<'a> {
|
|
type Error = TryFromFilteredError;
|
|
|
|
fn try_from(entity: &'a FilteredEntityMut<'_>) -> Result<Self, Self::Error> {
|
|
if !entity.access.has_read_all() {
|
|
Err(TryFromFilteredError::MissingReadAllAccess)
|
|
} else {
|
|
// SAFETY: check above guarantees read-only access to all components of the entity.
|
|
Ok(unsafe { EntityRef::new(entity.entity) })
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PartialEq for EntityRef<'_> {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.entity() == other.entity()
|
|
}
|
|
}
|
|
|
|
impl Eq for EntityRef<'_> {}
|
|
|
|
impl PartialOrd for EntityRef<'_> {
|
|
/// [`EntityRef`]'s comparison trait implementations match the underlying [`Entity`],
|
|
/// and cannot discern between different worlds.
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
Some(self.cmp(other))
|
|
}
|
|
}
|
|
|
|
impl Ord for EntityRef<'_> {
|
|
fn cmp(&self, other: &Self) -> Ordering {
|
|
self.entity().cmp(&other.entity())
|
|
}
|
|
}
|
|
|
|
impl Hash for EntityRef<'_> {
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
self.entity().hash(state);
|
|
}
|
|
}
|
|
|
|
impl ContainsEntity for EntityRef<'_> {
|
|
fn entity(&self) -> Entity {
|
|
self.id()
|
|
}
|
|
}
|
|
|
|
// SAFETY: This type represents one Entity. We implement the comparison traits based on that Entity.
|
|
unsafe impl EntityEquivalent for EntityRef<'_> {}
|
|
|
|
/// Provides mutable access to a single entity and all of its components.
|
|
///
|
|
/// Contrast with [`EntityWorldMut`], which 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> {
|
|
cell: 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.cell) }
|
|
}
|
|
|
|
/// Consumes `self` and returns read-only access to all of the entity's
|
|
/// components, with the world `'w` lifetime.
|
|
pub fn into_readonly(self) -> EntityRef<'w> {
|
|
EntityRef::from(self)
|
|
}
|
|
|
|
/// 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.cell.id()
|
|
}
|
|
|
|
/// Gets metadata indicating the location where the current entity is stored.
|
|
#[inline]
|
|
pub fn location(&self) -> EntityLocation {
|
|
self.cell.location()
|
|
}
|
|
|
|
/// Returns the archetype that the current entity belongs to.
|
|
#[inline]
|
|
pub fn archetype(&self) -> &Archetype {
|
|
self.cell.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.cell.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.cell.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()
|
|
}
|
|
|
|
/// Returns read-only components for the current entity that match the query `Q`.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity does not have the components required by the query `Q`.
|
|
pub fn components<Q: ReadOnlyQueryData>(&self) -> Q::Item<'_> {
|
|
self.as_readonly().components::<Q>()
|
|
}
|
|
|
|
/// Returns read-only components for the current entity that match the query `Q`,
|
|
/// or `None` if the entity does not have the components required by the query `Q`.
|
|
pub fn get_components<Q: ReadOnlyQueryData>(&self) -> Option<Q::Item<'_>> {
|
|
self.as_readonly().get_components::<Q>()
|
|
}
|
|
|
|
/// Consumes `self` and gets access to the component of type `T` with the
|
|
/// world `'w` lifetime for the current entity.
|
|
///
|
|
/// Returns `None` if the entity does not have a component of type `T`.
|
|
#[inline]
|
|
pub fn into_borrow<T: Component>(self) -> Option<&'w T> {
|
|
self.into_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()
|
|
}
|
|
|
|
/// Consumes `self` and gets access to the component of type `T` with world
|
|
/// `'w` lifetime for the current entity, including change detection information
|
|
/// as a [`Ref<'w>`].
|
|
///
|
|
/// Returns `None` if the entity does not have a component of type `T`.
|
|
#[inline]
|
|
pub fn into_ref<T: Component>(self) -> Option<Ref<'w, T>> {
|
|
self.into_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<Mutability = Mutable>>(&mut self) -> Option<Mut<'_, T>> {
|
|
// SAFETY: &mut self implies exclusive access for duration of returned value
|
|
unsafe { self.cell.get_mut() }
|
|
}
|
|
|
|
/// 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`.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// - `T` must be a mutable component
|
|
#[inline]
|
|
pub unsafe fn get_mut_assume_mutable<T: Component>(&mut self) -> Option<Mut<'_, T>> {
|
|
// SAFETY:
|
|
// - &mut self implies exclusive access for duration of returned value
|
|
// - Caller ensures `T` is a mutable component
|
|
unsafe { self.cell.get_mut_assume_mutable() }
|
|
}
|
|
|
|
/// Consumes self and gets mutable access to the component of type `T`
|
|
/// with the world `'w` lifetime for the current entity.
|
|
/// Returns `None` if the entity does not have a component of type `T`.
|
|
#[inline]
|
|
pub fn into_mut<T: Component<Mutability = Mutable>>(self) -> Option<Mut<'w, T>> {
|
|
// SAFETY: consuming `self` implies exclusive access
|
|
unsafe { self.cell.get_mut() }
|
|
}
|
|
|
|
/// 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`.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// - `T` must be a mutable component
|
|
#[inline]
|
|
pub unsafe fn into_mut_assume_mutable<T: Component>(self) -> Option<Mut<'w, T>> {
|
|
// SAFETY:
|
|
// - Consuming `self` implies exclusive access
|
|
// - Caller ensures `T` is a mutable component
|
|
unsafe { self.cell.get_mut_assume_mutable() }
|
|
}
|
|
|
|
/// 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)
|
|
}
|
|
|
|
/// Returns [untyped read-only reference(s)](Ptr) to component(s) for the
|
|
/// current entity, based on the given [`ComponentId`]s.
|
|
///
|
|
/// **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 untyped reference(s) to
|
|
/// component(s), and it's the job of the caller to ensure the correct
|
|
/// type(s) are dereferenced (if necessary).
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// Returns [`EntityComponentError::MissingComponent`] if the entity does
|
|
/// not have a component.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// For examples on how to use this method, see [`EntityRef::get_by_id`].
|
|
#[inline]
|
|
pub fn get_by_id<F: DynamicComponentFetch>(
|
|
&self,
|
|
component_ids: F,
|
|
) -> Result<F::Ref<'_>, EntityComponentError> {
|
|
self.as_readonly().get_by_id(component_ids)
|
|
}
|
|
|
|
/// Consumes `self` and returns [untyped read-only reference(s)](Ptr) to
|
|
/// component(s) with lifetime `'w` for the current entity, based on the
|
|
/// given [`ComponentId`]s.
|
|
///
|
|
/// **You should prefer to use the typed API [`EntityMut::into_borrow`]
|
|
/// where possible and only use this in cases where the actual component
|
|
/// types are not known at compile time.**
|
|
///
|
|
/// Unlike [`EntityMut::into_borrow`], this returns untyped reference(s) to
|
|
/// component(s), and it's the job of the caller to ensure the correct
|
|
/// type(s) are dereferenced (if necessary).
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// Returns [`EntityComponentError::MissingComponent`] if the entity does
|
|
/// not have a component.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// For examples on how to use this method, see [`EntityRef::get_by_id`].
|
|
#[inline]
|
|
pub fn into_borrow_by_id<F: DynamicComponentFetch>(
|
|
self,
|
|
component_ids: F,
|
|
) -> Result<F::Ref<'w>, EntityComponentError> {
|
|
self.into_readonly().get_by_id(component_ids)
|
|
}
|
|
|
|
/// Returns [untyped mutable reference(s)](MutUntyped) to component(s) for
|
|
/// the current entity, based on the given [`ComponentId`]s.
|
|
///
|
|
/// **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 untyped reference(s) to
|
|
/// component(s), and it's the job of the caller to ensure the correct
|
|
/// type(s) are dereferenced (if necessary).
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// - Returns [`EntityComponentError::MissingComponent`] if the entity does
|
|
/// not have a component.
|
|
/// - Returns [`EntityComponentError::AliasedMutability`] if a component
|
|
/// is requested multiple times.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ## Single [`ComponentId`]
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// #
|
|
/// # #[derive(Component, PartialEq, Debug)]
|
|
/// # pub struct Foo(i32);
|
|
/// # let mut world = World::new();
|
|
/// let entity = world.spawn(Foo(42)).id();
|
|
///
|
|
/// // Grab the component ID for `Foo` in whatever way you like.
|
|
/// let component_id = world.register_component::<Foo>();
|
|
///
|
|
/// // Then, get the component by ID.
|
|
/// let mut entity_mut = world.entity_mut(entity);
|
|
/// let mut ptr = entity_mut.get_mut_by_id(component_id)
|
|
/// # .unwrap();
|
|
/// # assert_eq!(unsafe { ptr.as_mut().deref_mut::<Foo>() }, &mut Foo(42));
|
|
/// ```
|
|
///
|
|
/// ## Array of [`ComponentId`]s
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// #
|
|
/// # #[derive(Component, PartialEq, Debug)]
|
|
/// # pub struct X(i32);
|
|
/// # #[derive(Component, PartialEq, Debug)]
|
|
/// # pub struct Y(i32);
|
|
/// # let mut world = World::new();
|
|
/// let entity = world.spawn((X(42), Y(10))).id();
|
|
///
|
|
/// // Grab the component IDs for `X` and `Y` in whatever way you like.
|
|
/// let x_id = world.register_component::<X>();
|
|
/// let y_id = world.register_component::<Y>();
|
|
///
|
|
/// // Then, get the components by ID. You'll receive a same-sized array.
|
|
/// let mut entity_mut = world.entity_mut(entity);
|
|
/// let Ok([mut x_ptr, mut y_ptr]) = entity_mut.get_mut_by_id([x_id, y_id]) else {
|
|
/// // Up to you to handle if a component is missing from the entity.
|
|
/// # unreachable!();
|
|
/// };
|
|
/// # assert_eq!((unsafe { x_ptr.as_mut().deref_mut::<X>() }, unsafe { y_ptr.as_mut().deref_mut::<Y>() }), (&mut X(42), &mut Y(10)));
|
|
/// ```
|
|
///
|
|
/// ## Slice of [`ComponentId`]s
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::{prelude::*, component::ComponentId, change_detection::MutUntyped};
|
|
/// #
|
|
/// # #[derive(Component, PartialEq, Debug)]
|
|
/// # pub struct X(i32);
|
|
/// # #[derive(Component, PartialEq, Debug)]
|
|
/// # pub struct Y(i32);
|
|
/// # let mut world = World::new();
|
|
/// let entity = world.spawn((X(42), Y(10))).id();
|
|
///
|
|
/// // Grab the component IDs for `X` and `Y` in whatever way you like.
|
|
/// let x_id = world.register_component::<X>();
|
|
/// let y_id = world.register_component::<Y>();
|
|
///
|
|
/// // Then, get the components by ID. You'll receive a vec of ptrs.
|
|
/// let mut entity_mut = world.entity_mut(entity);
|
|
/// let ptrs = entity_mut.get_mut_by_id(&[x_id, y_id] as &[ComponentId])
|
|
/// # .unwrap();
|
|
/// # let [mut x_ptr, mut y_ptr]: [MutUntyped; 2] = ptrs.try_into().unwrap();
|
|
/// # assert_eq!((unsafe { x_ptr.as_mut().deref_mut::<X>() }, unsafe { y_ptr.as_mut().deref_mut::<Y>() }), (&mut X(42), &mut Y(10)));
|
|
/// ```
|
|
///
|
|
/// ## [`HashSet`] of [`ComponentId`]s
|
|
///
|
|
/// ```
|
|
/// # use bevy_platform::collections::HashSet;
|
|
/// # use bevy_ecs::{prelude::*, component::ComponentId};
|
|
/// #
|
|
/// # #[derive(Component, PartialEq, Debug)]
|
|
/// # pub struct X(i32);
|
|
/// # #[derive(Component, PartialEq, Debug)]
|
|
/// # pub struct Y(i32);
|
|
/// # let mut world = World::new();
|
|
/// let entity = world.spawn((X(42), Y(10))).id();
|
|
///
|
|
/// // Grab the component IDs for `X` and `Y` in whatever way you like.
|
|
/// let x_id = world.register_component::<X>();
|
|
/// let y_id = world.register_component::<Y>();
|
|
///
|
|
/// // Then, get the components by ID. You'll receive a `HashMap` of ptrs.
|
|
/// let mut entity_mut = world.entity_mut(entity);
|
|
/// let mut ptrs = entity_mut.get_mut_by_id(&HashSet::from_iter([x_id, y_id]))
|
|
/// # .unwrap();
|
|
/// # let [Some(mut x_ptr), Some(mut y_ptr)] = ptrs.get_many_mut([&x_id, &y_id]) else { unreachable!() };
|
|
/// # assert_eq!((unsafe { x_ptr.as_mut().deref_mut::<X>() }, unsafe { y_ptr.as_mut().deref_mut::<Y>() }), (&mut X(42), &mut Y(10)));
|
|
/// ```
|
|
#[inline]
|
|
pub fn get_mut_by_id<F: DynamicComponentFetch>(
|
|
&mut self,
|
|
component_ids: F,
|
|
) -> Result<F::Mut<'_>, EntityComponentError> {
|
|
// SAFETY:
|
|
// - `&mut self` ensures that no references exist to this entity's components.
|
|
// - We have exclusive access to all components of this entity.
|
|
unsafe { component_ids.fetch_mut(self.cell) }
|
|
}
|
|
|
|
/// Returns [untyped mutable reference(s)](MutUntyped) to component(s) for
|
|
/// the current entity, based on the given [`ComponentId`]s.
|
|
/// Assumes the given [`ComponentId`]s refer to mutable components.
|
|
///
|
|
/// **You should prefer to use the typed API [`EntityMut::get_mut_assume_mutable`] where
|
|
/// possible and only use this in cases where the actual component types
|
|
/// are not known at compile time.**
|
|
///
|
|
/// Unlike [`EntityMut::get_mut_assume_mutable`], this returns untyped reference(s) to
|
|
/// component(s), and it's the job of the caller to ensure the correct
|
|
/// type(s) are dereferenced (if necessary).
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// - Returns [`EntityComponentError::MissingComponent`] if the entity does
|
|
/// not have a component.
|
|
/// - Returns [`EntityComponentError::AliasedMutability`] if a component
|
|
/// is requested multiple times.
|
|
///
|
|
/// # Safety
|
|
/// It is the callers responsibility to ensure that
|
|
/// - the provided [`ComponentId`]s must refer to mutable components.
|
|
#[inline]
|
|
pub unsafe fn get_mut_assume_mutable_by_id<F: DynamicComponentFetch>(
|
|
&mut self,
|
|
component_ids: F,
|
|
) -> Result<F::Mut<'_>, EntityComponentError> {
|
|
// SAFETY:
|
|
// - `&mut self` ensures that no references exist to this entity's components.
|
|
// - We have exclusive access to all components of this entity.
|
|
unsafe { component_ids.fetch_mut_assume_mutable(self.cell) }
|
|
}
|
|
|
|
/// Returns [untyped mutable reference](MutUntyped) to component for
|
|
/// the current entity, based on the given [`ComponentId`].
|
|
///
|
|
/// Unlike [`EntityMut::get_mut_by_id`], this method borrows &self instead of
|
|
/// &mut self, allowing the caller to access multiple components simultaneously.
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// - Returns [`EntityComponentError::MissingComponent`] if the entity does
|
|
/// not have a component.
|
|
/// - Returns [`EntityComponentError::AliasedMutability`] if a component
|
|
/// is requested multiple times.
|
|
///
|
|
/// # Safety
|
|
/// It is the callers responsibility to ensure that
|
|
/// - the [`UnsafeEntityCell`] has permission to access the component mutably
|
|
/// - no other references to the component exist at the same time
|
|
#[inline]
|
|
pub unsafe fn get_mut_by_id_unchecked<F: DynamicComponentFetch>(
|
|
&self,
|
|
component_ids: F,
|
|
) -> Result<F::Mut<'_>, EntityComponentError> {
|
|
// SAFETY:
|
|
// - The caller must ensure simultaneous access is limited
|
|
// - to components that are mutually independent.
|
|
unsafe { component_ids.fetch_mut(self.cell) }
|
|
}
|
|
|
|
/// Returns [untyped mutable reference](MutUntyped) to component for
|
|
/// the current entity, based on the given [`ComponentId`].
|
|
/// Assumes the given [`ComponentId`]s refer to mutable components.
|
|
///
|
|
/// Unlike [`EntityMut::get_mut_assume_mutable_by_id`], this method borrows &self instead of
|
|
/// &mut self, allowing the caller to access multiple components simultaneously.
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// - Returns [`EntityComponentError::MissingComponent`] if the entity does
|
|
/// not have a component.
|
|
/// - Returns [`EntityComponentError::AliasedMutability`] if a component
|
|
/// is requested multiple times.
|
|
///
|
|
/// # Safety
|
|
/// It is the callers responsibility to ensure that
|
|
/// - the [`UnsafeEntityCell`] has permission to access the component mutably
|
|
/// - no other references to the component exist at the same time
|
|
/// - the provided [`ComponentId`]s must refer to mutable components.
|
|
#[inline]
|
|
pub unsafe fn get_mut_assume_mutable_by_id_unchecked<F: DynamicComponentFetch>(
|
|
&self,
|
|
component_ids: F,
|
|
) -> Result<F::Mut<'_>, EntityComponentError> {
|
|
// SAFETY:
|
|
// - The caller must ensure simultaneous access is limited
|
|
// - to components that are mutually independent.
|
|
unsafe { component_ids.fetch_mut_assume_mutable(self.cell) }
|
|
}
|
|
|
|
/// Consumes `self` and returns [untyped mutable reference(s)](MutUntyped)
|
|
/// to component(s) with lifetime `'w` for the current entity, based on the
|
|
/// given [`ComponentId`]s.
|
|
///
|
|
/// **You should prefer to use the typed API [`EntityMut::into_mut`] where
|
|
/// possible and only use this in cases where the actual component types
|
|
/// are not known at compile time.**
|
|
///
|
|
/// Unlike [`EntityMut::into_mut`], this returns untyped reference(s) to
|
|
/// component(s), and it's the job of the caller to ensure the correct
|
|
/// type(s) are dereferenced (if necessary).
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// - Returns [`EntityComponentError::MissingComponent`] if the entity does
|
|
/// not have a component.
|
|
/// - Returns [`EntityComponentError::AliasedMutability`] if a component
|
|
/// is requested multiple times.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// For examples on how to use this method, see [`EntityMut::get_mut_by_id`].
|
|
#[inline]
|
|
pub fn into_mut_by_id<F: DynamicComponentFetch>(
|
|
self,
|
|
component_ids: F,
|
|
) -> Result<F::Mut<'w>, EntityComponentError> {
|
|
// SAFETY:
|
|
// - consuming `self` ensures that no references exist to this entity's components.
|
|
// - We have exclusive access to all components of this entity.
|
|
unsafe { component_ids.fetch_mut(self.cell) }
|
|
}
|
|
|
|
/// Consumes `self` and returns [untyped mutable reference(s)](MutUntyped)
|
|
/// to component(s) with lifetime `'w` for the current entity, based on the
|
|
/// given [`ComponentId`]s.
|
|
/// Assumes the given [`ComponentId`]s refer to mutable components.
|
|
///
|
|
/// **You should prefer to use the typed API [`EntityMut::into_mut_assume_mutable`] where
|
|
/// possible and only use this in cases where the actual component types
|
|
/// are not known at compile time.**
|
|
///
|
|
/// Unlike [`EntityMut::into_mut_assume_mutable`], this returns untyped reference(s) to
|
|
/// component(s), and it's the job of the caller to ensure the correct
|
|
/// type(s) are dereferenced (if necessary).
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// - Returns [`EntityComponentError::MissingComponent`] if the entity does
|
|
/// not have a component.
|
|
/// - Returns [`EntityComponentError::AliasedMutability`] if a component
|
|
/// is requested multiple times.
|
|
///
|
|
/// # Safety
|
|
/// It is the callers responsibility to ensure that
|
|
/// - the provided [`ComponentId`]s must refer to mutable components.
|
|
#[inline]
|
|
pub unsafe fn into_mut_assume_mutable_by_id<F: DynamicComponentFetch>(
|
|
self,
|
|
component_ids: F,
|
|
) -> Result<F::Mut<'w>, EntityComponentError> {
|
|
// SAFETY:
|
|
// - consuming `self` ensures that no references exist to this entity's components.
|
|
// - We have exclusive access to all components of this entity.
|
|
unsafe { component_ids.fetch_mut_assume_mutable(self.cell) }
|
|
}
|
|
|
|
/// Returns the source code location from which this entity has been spawned.
|
|
pub fn spawned_by(&self) -> MaybeLocation {
|
|
self.cell.spawned_by()
|
|
}
|
|
}
|
|
|
|
impl<'w> From<&'w mut EntityMut<'_>> for EntityMut<'w> {
|
|
fn from(entity: &'w mut EntityMut<'_>) -> Self {
|
|
entity.reborrow()
|
|
}
|
|
}
|
|
|
|
impl<'w> From<EntityWorldMut<'w>> for EntityMut<'w> {
|
|
fn from(entity: EntityWorldMut<'w>) -> Self {
|
|
// SAFETY: `EntityWorldMut` guarantees exclusive access to the entire world.
|
|
unsafe { EntityMut::new(entity.into_unsafe_entity_cell()) }
|
|
}
|
|
}
|
|
|
|
impl<'a> From<&'a mut EntityWorldMut<'_>> for EntityMut<'a> {
|
|
fn from(entity: &'a mut EntityWorldMut<'_>) -> Self {
|
|
// SAFETY: `EntityWorldMut` guarantees exclusive access to the entire world.
|
|
unsafe { EntityMut::new(entity.as_unsafe_entity_cell()) }
|
|
}
|
|
}
|
|
|
|
impl<'a> TryFrom<FilteredEntityMut<'a>> for EntityMut<'a> {
|
|
type Error = TryFromFilteredError;
|
|
|
|
fn try_from(entity: FilteredEntityMut<'a>) -> Result<Self, Self::Error> {
|
|
if !entity.access.has_read_all() {
|
|
Err(TryFromFilteredError::MissingReadAllAccess)
|
|
} else if !entity.access.has_write_all() {
|
|
Err(TryFromFilteredError::MissingWriteAllAccess)
|
|
} else {
|
|
// SAFETY: check above guarantees exclusive access to all components of the entity.
|
|
Ok(unsafe { EntityMut::new(entity.entity) })
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> TryFrom<&'a mut FilteredEntityMut<'_>> for EntityMut<'a> {
|
|
type Error = TryFromFilteredError;
|
|
|
|
fn try_from(entity: &'a mut FilteredEntityMut<'_>) -> Result<Self, Self::Error> {
|
|
if !entity.access.has_read_all() {
|
|
Err(TryFromFilteredError::MissingReadAllAccess)
|
|
} else if !entity.access.has_write_all() {
|
|
Err(TryFromFilteredError::MissingWriteAllAccess)
|
|
} else {
|
|
// SAFETY: check above guarantees exclusive access to all components of the entity.
|
|
Ok(unsafe { EntityMut::new(entity.entity) })
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PartialEq for EntityMut<'_> {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.entity() == other.entity()
|
|
}
|
|
}
|
|
|
|
impl Eq for EntityMut<'_> {}
|
|
|
|
impl PartialOrd for EntityMut<'_> {
|
|
/// [`EntityMut`]'s comparison trait implementations match the underlying [`Entity`],
|
|
/// and cannot discern between different worlds.
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
Some(self.cmp(other))
|
|
}
|
|
}
|
|
|
|
impl Ord for EntityMut<'_> {
|
|
fn cmp(&self, other: &Self) -> Ordering {
|
|
self.entity().cmp(&other.entity())
|
|
}
|
|
}
|
|
|
|
impl Hash for EntityMut<'_> {
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
self.entity().hash(state);
|
|
}
|
|
}
|
|
|
|
impl ContainsEntity for EntityMut<'_> {
|
|
fn entity(&self) -> Entity {
|
|
self.id()
|
|
}
|
|
}
|
|
|
|
// SAFETY: This type represents one Entity. We implement the comparison traits based on that Entity.
|
|
unsafe impl EntityEquivalent for EntityMut<'_> {}
|
|
|
|
/// A mutable reference to a particular [`Entity`], and the entire world.
|
|
///
|
|
/// This is essentially a performance-optimized `(Entity, &mut World)` tuple,
|
|
/// which caches the [`EntityLocation`] to reduce duplicate lookups.
|
|
///
|
|
/// Since this type provides mutable access to the entire world, only one
|
|
/// [`EntityWorldMut`] can exist at a time for a given world.
|
|
///
|
|
/// See also [`EntityMut`], which allows disjoint mutable access to multiple
|
|
/// entities at once. Unlike `EntityMut`, this type allows adding and
|
|
/// removing components, and despawning the entity.
|
|
pub struct EntityWorldMut<'w> {
|
|
world: &'w mut World,
|
|
entity: Entity,
|
|
location: EntityLocation,
|
|
}
|
|
|
|
impl<'w> EntityWorldMut<'w> {
|
|
#[track_caller]
|
|
#[inline(never)]
|
|
#[cold]
|
|
fn panic_despawned(&self) -> ! {
|
|
panic!(
|
|
"Entity {} {}",
|
|
self.entity,
|
|
self.world
|
|
.entities()
|
|
.entity_does_not_exist_error_details(self.entity)
|
|
);
|
|
}
|
|
|
|
#[inline(always)]
|
|
#[track_caller]
|
|
pub(crate) fn assert_not_despawned(&self) {
|
|
if self.location.archetype_id == ArchetypeId::INVALID {
|
|
self.panic_despawned();
|
|
}
|
|
}
|
|
|
|
fn as_unsafe_entity_cell_readonly(&self) -> UnsafeEntityCell<'_> {
|
|
self.assert_not_despawned();
|
|
UnsafeEntityCell::new(
|
|
self.world.as_unsafe_world_cell_readonly(),
|
|
self.entity,
|
|
self.location,
|
|
)
|
|
}
|
|
fn as_unsafe_entity_cell(&mut self) -> UnsafeEntityCell<'_> {
|
|
self.assert_not_despawned();
|
|
UnsafeEntityCell::new(
|
|
self.world.as_unsafe_world_cell(),
|
|
self.entity,
|
|
self.location,
|
|
)
|
|
}
|
|
fn into_unsafe_entity_cell(self) -> UnsafeEntityCell<'w> {
|
|
self.assert_not_despawned();
|
|
UnsafeEntityCell::new(
|
|
self.world.as_unsafe_world_cell(),
|
|
self.entity,
|
|
self.location,
|
|
)
|
|
}
|
|
|
|
/// # Safety
|
|
///
|
|
/// - `entity` must be valid for `world`: the generation should match that of the entity at the same index.
|
|
/// - `location` must be sourced from `world`'s `Entities` and must exactly match the location for `entity`
|
|
///
|
|
/// The above is trivially satisfied if `location` was sourced from `world.entities().get(entity)`.
|
|
#[inline]
|
|
pub(crate) unsafe fn new(
|
|
world: &'w mut World,
|
|
entity: Entity,
|
|
location: EntityLocation,
|
|
) -> Self {
|
|
debug_assert!(world.entities().contains(entity));
|
|
debug_assert_eq!(world.entities().get(entity), Some(location));
|
|
|
|
EntityWorldMut {
|
|
world,
|
|
entity,
|
|
location,
|
|
}
|
|
}
|
|
|
|
/// Consumes `self` and returns read-only access to all of the entity's
|
|
/// components, with the world `'w` lifetime.
|
|
pub fn into_readonly(self) -> EntityRef<'w> {
|
|
EntityRef::from(self)
|
|
}
|
|
|
|
/// Gets read-only access to all of the entity's components.
|
|
pub fn as_readonly(&self) -> EntityRef<'_> {
|
|
EntityRef::from(self)
|
|
}
|
|
|
|
/// Consumes `self` and returns non-structural mutable access to all of the
|
|
/// entity's components, with the world `'w` lifetime.
|
|
pub fn into_mutable(self) -> EntityMut<'w> {
|
|
EntityMut::from(self)
|
|
}
|
|
|
|
/// Gets non-structural mutable access to all of the entity's components.
|
|
pub fn as_mutable(&mut self) -> EntityMut<'_> {
|
|
EntityMut::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.entity
|
|
}
|
|
|
|
/// Gets metadata indicating the location where the current entity is stored.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[inline]
|
|
pub fn location(&self) -> EntityLocation {
|
|
self.assert_not_despawned();
|
|
self.location
|
|
}
|
|
|
|
/// Returns the archetype that the current entity belongs to.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[inline]
|
|
pub fn archetype(&self) -> &Archetype {
|
|
self.assert_not_despawned();
|
|
&self.world.archetypes[self.location.archetype_id]
|
|
}
|
|
|
|
/// 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`].
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[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`].
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[inline]
|
|
pub fn contains_id(&self, component_id: ComponentId) -> bool {
|
|
self.as_unsafe_entity_cell_readonly()
|
|
.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`].
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[inline]
|
|
pub fn contains_type_id(&self, type_id: TypeId) -> bool {
|
|
self.as_unsafe_entity_cell_readonly()
|
|
.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`.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[inline]
|
|
pub fn get<T: Component>(&self) -> Option<&'_ T> {
|
|
self.as_readonly().get()
|
|
}
|
|
|
|
/// Returns read-only components for the current entity that match the query `Q`.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity does not have the components required by the query `Q` or if the entity
|
|
/// has been despawned while this `EntityWorldMut` is still alive.
|
|
#[inline]
|
|
pub fn components<Q: ReadOnlyQueryData>(&self) -> Q::Item<'_> {
|
|
self.as_readonly().components::<Q>()
|
|
}
|
|
|
|
/// Returns read-only components for the current entity that match the query `Q`,
|
|
/// or `None` if the entity does not have the components required by the query `Q`.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[inline]
|
|
pub fn get_components<Q: ReadOnlyQueryData>(&self) -> Option<Q::Item<'_>> {
|
|
self.as_readonly().get_components::<Q>()
|
|
}
|
|
|
|
/// Consumes `self` and gets access to the component of type `T` with
|
|
/// the world `'w` lifetime for the current entity.
|
|
/// Returns `None` if the entity does not have a component of type `T`.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[inline]
|
|
pub fn into_borrow<T: Component>(self) -> Option<&'w T> {
|
|
self.into_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`.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[inline]
|
|
pub fn get_ref<T: Component>(&self) -> Option<Ref<'_, T>> {
|
|
self.as_readonly().get_ref()
|
|
}
|
|
|
|
/// Consumes `self` and gets access to the component of type `T`
|
|
/// with the world `'w` lifetime for the current entity,
|
|
/// including change detection information as a [`Ref`].
|
|
///
|
|
/// Returns `None` if the entity does not have a component of type `T`.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[inline]
|
|
pub fn into_ref<T: Component>(self) -> Option<Ref<'w, T>> {
|
|
self.into_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`.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[inline]
|
|
pub fn get_mut<T: Component<Mutability = Mutable>>(&mut self) -> Option<Mut<'_, T>> {
|
|
self.as_mutable().into_mut()
|
|
}
|
|
|
|
/// Temporarily removes a [`Component`] `T` from this [`Entity`] and runs the
|
|
/// provided closure on it, returning the result if `T` was available.
|
|
/// This will trigger the `OnRemove` and `OnReplace` component hooks without
|
|
/// causing an archetype move.
|
|
///
|
|
/// This is most useful with immutable components, where removal and reinsertion
|
|
/// is the only way to modify a value.
|
|
///
|
|
/// If you do not need to ensure the above hooks are triggered, and your component
|
|
/// is mutable, prefer using [`get_mut`](EntityWorldMut::get_mut).
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```rust
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// #
|
|
/// #[derive(Component, PartialEq, Eq, Debug)]
|
|
/// #[component(immutable)]
|
|
/// struct Foo(bool);
|
|
///
|
|
/// # let mut world = World::default();
|
|
/// # world.register_component::<Foo>();
|
|
/// #
|
|
/// # let entity = world.spawn(Foo(false)).id();
|
|
/// #
|
|
/// # let mut entity = world.entity_mut(entity);
|
|
/// #
|
|
/// # assert_eq!(entity.get::<Foo>(), Some(&Foo(false)));
|
|
/// #
|
|
/// entity.modify_component(|foo: &mut Foo| {
|
|
/// foo.0 = true;
|
|
/// });
|
|
/// #
|
|
/// # assert_eq!(entity.get::<Foo>(), Some(&Foo(true)));
|
|
/// ```
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[inline]
|
|
pub fn modify_component<T: Component, R>(&mut self, f: impl FnOnce(&mut T) -> R) -> Option<R> {
|
|
self.assert_not_despawned();
|
|
|
|
let result = self
|
|
.world
|
|
.modify_component(self.entity, f)
|
|
.expect("entity access must be valid")?;
|
|
|
|
self.update_location();
|
|
|
|
Some(result)
|
|
}
|
|
|
|
/// Temporarily removes a [`Component`] `T` from this [`Entity`] and runs the
|
|
/// provided closure on it, returning the result if `T` was available.
|
|
/// This will trigger the `OnRemove` and `OnReplace` component hooks without
|
|
/// causing an archetype move.
|
|
///
|
|
/// This is most useful with immutable components, where removal and reinsertion
|
|
/// is the only way to modify a value.
|
|
///
|
|
/// If you do not need to ensure the above hooks are triggered, and your component
|
|
/// is mutable, prefer using [`get_mut`](EntityWorldMut::get_mut).
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[inline]
|
|
pub fn modify_component_by_id<R>(
|
|
&mut self,
|
|
component_id: ComponentId,
|
|
f: impl for<'a> FnOnce(MutUntyped<'a>) -> R,
|
|
) -> Option<R> {
|
|
self.assert_not_despawned();
|
|
|
|
let result = self
|
|
.world
|
|
.modify_component_by_id(self.entity, component_id, f)
|
|
.expect("entity access must be valid")?;
|
|
|
|
self.update_location();
|
|
|
|
Some(result)
|
|
}
|
|
|
|
/// 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`.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// - `T` must be a mutable component
|
|
#[inline]
|
|
pub unsafe fn get_mut_assume_mutable<T: Component>(&mut self) -> Option<Mut<'_, T>> {
|
|
self.as_mutable().into_mut_assume_mutable()
|
|
}
|
|
|
|
/// Consumes `self` and gets mutable access to the component of type `T`
|
|
/// with the world `'w` lifetime for the current entity.
|
|
/// Returns `None` if the entity does not have a component of type `T`.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[inline]
|
|
pub fn into_mut<T: Component<Mutability = Mutable>>(self) -> Option<Mut<'w, T>> {
|
|
// SAFETY: consuming `self` implies exclusive access
|
|
unsafe { self.into_unsafe_entity_cell().get_mut() }
|
|
}
|
|
|
|
/// Consumes `self` and gets mutable access to the component of type `T`
|
|
/// with the world `'w` lifetime for the current entity.
|
|
/// Returns `None` if the entity does not have a component of type `T`.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// - `T` must be a mutable component
|
|
#[inline]
|
|
pub unsafe fn into_mut_assume_mutable<T: Component>(self) -> Option<Mut<'w, T>> {
|
|
// SAFETY: consuming `self` implies exclusive access
|
|
unsafe { self.into_unsafe_entity_cell().get_mut_assume_mutable() }
|
|
}
|
|
|
|
/// Gets a reference to the resource of the given type
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// Panics if the resource does not exist.
|
|
/// Use [`get_resource`](EntityWorldMut::get_resource) instead if you want to handle this case.
|
|
#[inline]
|
|
#[track_caller]
|
|
pub fn resource<R: Resource>(&self) -> &R {
|
|
self.world.resource::<R>()
|
|
}
|
|
|
|
/// Gets a mutable reference to the resource of the given type
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// Panics if the resource does not exist.
|
|
/// Use [`get_resource_mut`](World::get_resource_mut) instead if you want to handle this case.
|
|
///
|
|
/// If you want to instead insert a value if the resource does not exist,
|
|
/// use [`get_resource_or_insert_with`](World::get_resource_or_insert_with).
|
|
#[inline]
|
|
#[track_caller]
|
|
pub fn resource_mut<R: Resource>(&mut self) -> Mut<'_, R> {
|
|
self.world.resource_mut::<R>()
|
|
}
|
|
|
|
/// Gets a reference to the resource of the given type if it exists
|
|
#[inline]
|
|
pub fn get_resource<R: Resource>(&self) -> Option<&R> {
|
|
self.world.get_resource()
|
|
}
|
|
|
|
/// Gets a mutable reference to the resource of the given type if it exists
|
|
#[inline]
|
|
pub fn get_resource_mut<R: Resource>(&mut self) -> Option<Mut<'_, R>> {
|
|
self.world.get_resource_mut()
|
|
}
|
|
|
|
/// Retrieves the change ticks for the given component. This can be useful for implementing change
|
|
/// detection in custom runtimes.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[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.**
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[inline]
|
|
pub fn get_change_ticks_by_id(&self, component_id: ComponentId) -> Option<ComponentTicks> {
|
|
self.as_readonly().get_change_ticks_by_id(component_id)
|
|
}
|
|
|
|
/// Returns [untyped read-only reference(s)](Ptr) to component(s) for the
|
|
/// current entity, based on the given [`ComponentId`]s.
|
|
///
|
|
/// **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 untyped reference(s) to
|
|
/// component(s), and it's the job of the caller to ensure the correct
|
|
/// type(s) are dereferenced (if necessary).
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// Returns [`EntityComponentError::MissingComponent`] if the entity does
|
|
/// not have a component.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// For examples on how to use this method, see [`EntityRef::get_by_id`].
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[inline]
|
|
pub fn get_by_id<F: DynamicComponentFetch>(
|
|
&self,
|
|
component_ids: F,
|
|
) -> Result<F::Ref<'_>, EntityComponentError> {
|
|
self.as_readonly().get_by_id(component_ids)
|
|
}
|
|
|
|
/// Consumes `self` and returns [untyped read-only reference(s)](Ptr) to
|
|
/// component(s) with lifetime `'w` for the current entity, based on the
|
|
/// given [`ComponentId`]s.
|
|
///
|
|
/// **You should prefer to use the typed API [`EntityWorldMut::into_borrow`]
|
|
/// where possible and only use this in cases where the actual component
|
|
/// types are not known at compile time.**
|
|
///
|
|
/// Unlike [`EntityWorldMut::into_borrow`], this returns untyped reference(s) to
|
|
/// component(s), and it's the job of the caller to ensure the correct
|
|
/// type(s) are dereferenced (if necessary).
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// Returns [`EntityComponentError::MissingComponent`] if the entity does
|
|
/// not have a component.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// For examples on how to use this method, see [`EntityRef::get_by_id`].
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[inline]
|
|
pub fn into_borrow_by_id<F: DynamicComponentFetch>(
|
|
self,
|
|
component_ids: F,
|
|
) -> Result<F::Ref<'w>, EntityComponentError> {
|
|
self.into_readonly().get_by_id(component_ids)
|
|
}
|
|
|
|
/// Returns [untyped mutable reference(s)](MutUntyped) to component(s) for
|
|
/// the current entity, based on the given [`ComponentId`]s.
|
|
///
|
|
/// **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 untyped reference(s) to
|
|
/// component(s), and it's the job of the caller to ensure the correct
|
|
/// type(s) are dereferenced (if necessary).
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// - Returns [`EntityComponentError::MissingComponent`] if the entity does
|
|
/// not have a component.
|
|
/// - Returns [`EntityComponentError::AliasedMutability`] if a component
|
|
/// is requested multiple times.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// For examples on how to use this method, see [`EntityMut::get_mut_by_id`].
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[inline]
|
|
pub fn get_mut_by_id<F: DynamicComponentFetch>(
|
|
&mut self,
|
|
component_ids: F,
|
|
) -> Result<F::Mut<'_>, EntityComponentError> {
|
|
self.as_mutable().into_mut_by_id(component_ids)
|
|
}
|
|
|
|
/// Returns [untyped mutable reference(s)](MutUntyped) to component(s) for
|
|
/// the current entity, based on the given [`ComponentId`]s.
|
|
/// Assumes the given [`ComponentId`]s refer to mutable components.
|
|
///
|
|
/// **You should prefer to use the typed API [`EntityWorldMut::get_mut_assume_mutable`] where
|
|
/// possible and only use this in cases where the actual component types
|
|
/// are not known at compile time.**
|
|
///
|
|
/// Unlike [`EntityWorldMut::get_mut_assume_mutable`], this returns untyped reference(s) to
|
|
/// component(s), and it's the job of the caller to ensure the correct
|
|
/// type(s) are dereferenced (if necessary).
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// - Returns [`EntityComponentError::MissingComponent`] if the entity does
|
|
/// not have a component.
|
|
/// - Returns [`EntityComponentError::AliasedMutability`] if a component
|
|
/// is requested multiple times.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
///
|
|
/// # Safety
|
|
/// It is the callers responsibility to ensure that
|
|
/// - the provided [`ComponentId`]s must refer to mutable components.
|
|
#[inline]
|
|
pub unsafe fn get_mut_assume_mutable_by_id<F: DynamicComponentFetch>(
|
|
&mut self,
|
|
component_ids: F,
|
|
) -> Result<F::Mut<'_>, EntityComponentError> {
|
|
self.as_mutable()
|
|
.into_mut_assume_mutable_by_id(component_ids)
|
|
}
|
|
|
|
/// Consumes `self` and returns [untyped mutable reference(s)](MutUntyped)
|
|
/// to component(s) with lifetime `'w` for the current entity, based on the
|
|
/// given [`ComponentId`]s.
|
|
///
|
|
/// **You should prefer to use the typed API [`EntityWorldMut::into_mut`] where
|
|
/// possible and only use this in cases where the actual component types
|
|
/// are not known at compile time.**
|
|
///
|
|
/// Unlike [`EntityWorldMut::into_mut`], this returns untyped reference(s) to
|
|
/// component(s), and it's the job of the caller to ensure the correct
|
|
/// type(s) are dereferenced (if necessary).
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// - Returns [`EntityComponentError::MissingComponent`] if the entity does
|
|
/// not have a component.
|
|
/// - Returns [`EntityComponentError::AliasedMutability`] if a component
|
|
/// is requested multiple times.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// For examples on how to use this method, see [`EntityMut::get_mut_by_id`].
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[inline]
|
|
pub fn into_mut_by_id<F: DynamicComponentFetch>(
|
|
self,
|
|
component_ids: F,
|
|
) -> Result<F::Mut<'w>, EntityComponentError> {
|
|
self.into_mutable().into_mut_by_id(component_ids)
|
|
}
|
|
|
|
/// Consumes `self` and returns [untyped mutable reference(s)](MutUntyped)
|
|
/// to component(s) with lifetime `'w` for the current entity, based on the
|
|
/// given [`ComponentId`]s.
|
|
/// Assumes the given [`ComponentId`]s refer to mutable components.
|
|
///
|
|
/// **You should prefer to use the typed API [`EntityWorldMut::into_mut_assume_mutable`] where
|
|
/// possible and only use this in cases where the actual component types
|
|
/// are not known at compile time.**
|
|
///
|
|
/// Unlike [`EntityWorldMut::into_mut_assume_mutable`], this returns untyped reference(s) to
|
|
/// component(s), and it's the job of the caller to ensure the correct
|
|
/// type(s) are dereferenced (if necessary).
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// - Returns [`EntityComponentError::MissingComponent`] if the entity does
|
|
/// not have a component.
|
|
/// - Returns [`EntityComponentError::AliasedMutability`] if a component
|
|
/// is requested multiple times.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
///
|
|
/// # Safety
|
|
/// It is the callers responsibility to ensure that
|
|
/// - the provided [`ComponentId`]s must refer to mutable components.
|
|
#[inline]
|
|
pub unsafe fn into_mut_assume_mutable_by_id<F: DynamicComponentFetch>(
|
|
self,
|
|
component_ids: F,
|
|
) -> Result<F::Mut<'w>, EntityComponentError> {
|
|
self.into_mutable()
|
|
.into_mut_assume_mutable_by_id(component_ids)
|
|
}
|
|
|
|
/// Adds a [`Bundle`] of components to the entity.
|
|
///
|
|
/// This will overwrite any previous value(s) of the same component type.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[track_caller]
|
|
pub fn insert<T: Bundle>(&mut self, bundle: T) -> &mut Self {
|
|
self.insert_with_caller(
|
|
bundle,
|
|
InsertMode::Replace,
|
|
MaybeLocation::caller(),
|
|
RelationshipHookMode::Run,
|
|
)
|
|
}
|
|
|
|
/// Adds a [`Bundle`] of components to the entity.
|
|
/// [`Relationship`](crate::relationship::Relationship) components in the bundle will follow the configuration
|
|
/// in `relationship_hook_mode`.
|
|
///
|
|
/// This will overwrite any previous value(s) of the same component type.
|
|
///
|
|
/// # Warning
|
|
///
|
|
/// This can easily break the integrity of relationships. This is intended to be used for cloning and spawning code internals,
|
|
/// not most user-facing scenarios.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[track_caller]
|
|
pub fn insert_with_relationship_hook_mode<T: Bundle>(
|
|
&mut self,
|
|
bundle: T,
|
|
relationship_hook_mode: RelationshipHookMode,
|
|
) -> &mut Self {
|
|
self.insert_with_caller(
|
|
bundle,
|
|
InsertMode::Replace,
|
|
MaybeLocation::caller(),
|
|
relationship_hook_mode,
|
|
)
|
|
}
|
|
|
|
/// Adds a [`Bundle`] of components to the entity without overwriting.
|
|
///
|
|
/// This will leave any previous value(s) of the same component type
|
|
/// unchanged.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[track_caller]
|
|
pub fn insert_if_new<T: Bundle>(&mut self, bundle: T) -> &mut Self {
|
|
self.insert_with_caller(
|
|
bundle,
|
|
InsertMode::Keep,
|
|
MaybeLocation::caller(),
|
|
RelationshipHookMode::Run,
|
|
)
|
|
}
|
|
|
|
/// Split into a new function so we can pass the calling location into the function when using
|
|
/// as a command.
|
|
#[inline]
|
|
pub(crate) fn insert_with_caller<T: Bundle>(
|
|
&mut self,
|
|
bundle: T,
|
|
mode: InsertMode,
|
|
caller: MaybeLocation,
|
|
relationship_hook_mode: RelationshipHookMode,
|
|
) -> &mut Self {
|
|
self.assert_not_despawned();
|
|
let change_tick = self.world.change_tick();
|
|
let mut bundle_inserter =
|
|
BundleInserter::new::<T>(self.world, self.location.archetype_id, change_tick);
|
|
// SAFETY: location matches current entity. `T` matches `bundle_info`
|
|
let (location, after_effect) = unsafe {
|
|
bundle_inserter.insert(
|
|
self.entity,
|
|
self.location,
|
|
bundle,
|
|
mode,
|
|
caller,
|
|
relationship_hook_mode,
|
|
)
|
|
};
|
|
self.location = location;
|
|
self.world.flush();
|
|
self.update_location();
|
|
after_effect.apply(self);
|
|
self
|
|
}
|
|
|
|
/// Inserts a dynamic [`Component`] into the entity.
|
|
///
|
|
/// This will overwrite any previous value(s) of the same component type.
|
|
///
|
|
/// You should prefer to use the typed API [`EntityWorldMut::insert`] where possible.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// - [`ComponentId`] must be from the same world as [`EntityWorldMut`]
|
|
/// - [`OwningPtr`] must be a valid reference to the type represented by [`ComponentId`]
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[track_caller]
|
|
pub unsafe fn insert_by_id(
|
|
&mut self,
|
|
component_id: ComponentId,
|
|
component: OwningPtr<'_>,
|
|
) -> &mut Self {
|
|
self.insert_by_id_with_caller(
|
|
component_id,
|
|
component,
|
|
InsertMode::Replace,
|
|
MaybeLocation::caller(),
|
|
RelationshipHookMode::Run,
|
|
)
|
|
}
|
|
|
|
/// # Safety
|
|
///
|
|
/// - [`ComponentId`] must be from the same world as [`EntityWorldMut`]
|
|
/// - [`OwningPtr`] must be a valid reference to the type represented by [`ComponentId`]
|
|
#[inline]
|
|
pub(crate) unsafe fn insert_by_id_with_caller(
|
|
&mut self,
|
|
component_id: ComponentId,
|
|
component: OwningPtr<'_>,
|
|
mode: InsertMode,
|
|
caller: MaybeLocation,
|
|
relationship_hook_insert_mode: RelationshipHookMode,
|
|
) -> &mut Self {
|
|
self.assert_not_despawned();
|
|
let change_tick = self.world.change_tick();
|
|
let bundle_id = self.world.bundles.init_component_info(
|
|
&mut self.world.storages,
|
|
&self.world.components,
|
|
component_id,
|
|
);
|
|
let storage_type = self.world.bundles.get_storage_unchecked(bundle_id);
|
|
|
|
let bundle_inserter = BundleInserter::new_with_id(
|
|
self.world,
|
|
self.location.archetype_id,
|
|
bundle_id,
|
|
change_tick,
|
|
);
|
|
|
|
self.location = insert_dynamic_bundle(
|
|
bundle_inserter,
|
|
self.entity,
|
|
self.location,
|
|
Some(component).into_iter(),
|
|
Some(storage_type).iter().cloned(),
|
|
mode,
|
|
caller,
|
|
relationship_hook_insert_mode,
|
|
);
|
|
self.world.flush();
|
|
self.update_location();
|
|
self
|
|
}
|
|
|
|
/// Inserts a dynamic [`Bundle`] into the entity.
|
|
///
|
|
/// This will overwrite any previous value(s) of the same component type.
|
|
///
|
|
/// You should prefer to use the typed API [`EntityWorldMut::insert`] where possible.
|
|
/// If your [`Bundle`] only has one component, use the cached API [`EntityWorldMut::insert_by_id`].
|
|
///
|
|
/// If possible, pass a sorted slice of `ComponentId` to maximize caching potential.
|
|
///
|
|
/// # Safety
|
|
/// - Each [`ComponentId`] must be from the same world as [`EntityWorldMut`]
|
|
/// - Each [`OwningPtr`] must be a valid reference to the type represented by [`ComponentId`]
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[track_caller]
|
|
pub unsafe fn insert_by_ids<'a, I: Iterator<Item = OwningPtr<'a>>>(
|
|
&mut self,
|
|
component_ids: &[ComponentId],
|
|
iter_components: I,
|
|
) -> &mut Self {
|
|
self.insert_by_ids_internal(component_ids, iter_components, RelationshipHookMode::Run)
|
|
}
|
|
|
|
#[track_caller]
|
|
pub(crate) unsafe fn insert_by_ids_internal<'a, I: Iterator<Item = OwningPtr<'a>>>(
|
|
&mut self,
|
|
component_ids: &[ComponentId],
|
|
iter_components: I,
|
|
relationship_hook_insert_mode: RelationshipHookMode,
|
|
) -> &mut Self {
|
|
self.assert_not_despawned();
|
|
let change_tick = self.world.change_tick();
|
|
let bundle_id = self.world.bundles.init_dynamic_info(
|
|
&mut self.world.storages,
|
|
&self.world.components,
|
|
component_ids,
|
|
);
|
|
let mut storage_types =
|
|
core::mem::take(self.world.bundles.get_storages_unchecked(bundle_id));
|
|
let bundle_inserter = BundleInserter::new_with_id(
|
|
self.world,
|
|
self.location.archetype_id,
|
|
bundle_id,
|
|
change_tick,
|
|
);
|
|
|
|
self.location = insert_dynamic_bundle(
|
|
bundle_inserter,
|
|
self.entity,
|
|
self.location,
|
|
iter_components,
|
|
(*storage_types).iter().cloned(),
|
|
InsertMode::Replace,
|
|
MaybeLocation::caller(),
|
|
relationship_hook_insert_mode,
|
|
);
|
|
*self.world.bundles.get_storages_unchecked(bundle_id) = core::mem::take(&mut storage_types);
|
|
self.world.flush();
|
|
self.update_location();
|
|
self
|
|
}
|
|
|
|
/// Removes all components in the [`Bundle`] from the entity and returns their previous values.
|
|
///
|
|
/// **Note:** If the entity does not have every component in the bundle, this method will not
|
|
/// remove any of them.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[must_use]
|
|
#[track_caller]
|
|
pub fn take<T: Bundle + BundleFromComponents>(&mut self) -> Option<T> {
|
|
self.assert_not_despawned();
|
|
let entity = self.entity;
|
|
let location = self.location;
|
|
|
|
let mut remover =
|
|
// SAFETY: The archetype id must be valid since this entity is in it.
|
|
unsafe { BundleRemover::new::<T>(self.world, self.location.archetype_id, true) }?;
|
|
// SAFETY: The passed location has the sane archetype as the remover, since they came from the same location.
|
|
let (new_location, result) = unsafe {
|
|
remover.remove(
|
|
entity,
|
|
location,
|
|
MaybeLocation::caller(),
|
|
|sets, table, components, bundle_components| {
|
|
let mut bundle_components = bundle_components.iter().copied();
|
|
(
|
|
false,
|
|
T::from_components(&mut (sets, table), &mut |(sets, table)| {
|
|
let component_id = bundle_components.next().unwrap();
|
|
// SAFETY: the component existed to be removed, so its id must be valid.
|
|
let component_info = components.get_info_unchecked(component_id);
|
|
match component_info.storage_type() {
|
|
StorageType::Table => {
|
|
table
|
|
.as_mut()
|
|
// SAFETY: The table must be valid if the component is in it.
|
|
.debug_checked_unwrap()
|
|
// SAFETY: The remover is cleaning this up.
|
|
.take_component(component_id, location.table_row)
|
|
}
|
|
StorageType::SparseSet => sets
|
|
.get_mut(component_id)
|
|
.unwrap()
|
|
.remove_and_forget(entity)
|
|
.unwrap(),
|
|
}
|
|
}),
|
|
)
|
|
},
|
|
)
|
|
};
|
|
self.location = new_location;
|
|
|
|
self.world.flush();
|
|
self.update_location();
|
|
Some(result)
|
|
}
|
|
|
|
/// Removes any components in the [`Bundle`] from the entity.
|
|
///
|
|
/// See [`EntityCommands::remove`](crate::system::EntityCommands::remove) for more details.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[track_caller]
|
|
pub fn remove<T: Bundle>(&mut self) -> &mut Self {
|
|
self.remove_with_caller::<T>(MaybeLocation::caller())
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn remove_with_caller<T: Bundle>(&mut self, caller: MaybeLocation) -> &mut Self {
|
|
self.assert_not_despawned();
|
|
|
|
let Some(mut remover) =
|
|
// SAFETY: The archetype id must be valid since this entity is in it.
|
|
(unsafe { BundleRemover::new::<T>(self.world, self.location.archetype_id, false) })
|
|
else {
|
|
return self;
|
|
};
|
|
// SAFETY: The remover archetype came from the passed location and the removal can not fail.
|
|
let new_location = unsafe {
|
|
remover.remove(
|
|
self.entity,
|
|
self.location,
|
|
caller,
|
|
BundleRemover::empty_pre_remove,
|
|
)
|
|
}
|
|
.0;
|
|
|
|
self.location = new_location;
|
|
self.world.flush();
|
|
self.update_location();
|
|
self
|
|
}
|
|
|
|
/// Removes all components in the [`Bundle`] and remove all required components for each component in the bundle
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[track_caller]
|
|
pub fn remove_with_requires<T: Bundle>(&mut self) -> &mut Self {
|
|
self.remove_with_requires_with_caller::<T>(MaybeLocation::caller())
|
|
}
|
|
|
|
pub(crate) fn remove_with_requires_with_caller<T: Bundle>(
|
|
&mut self,
|
|
caller: MaybeLocation,
|
|
) -> &mut Self {
|
|
self.assert_not_despawned();
|
|
let storages = &mut self.world.storages;
|
|
let bundles = &mut self.world.bundles;
|
|
// SAFETY: These come from the same world.
|
|
let mut registrator = unsafe {
|
|
ComponentsRegistrator::new(&mut self.world.components, &mut self.world.component_ids)
|
|
};
|
|
let bundle_id = bundles.register_contributed_bundle_info::<T>(&mut registrator, storages);
|
|
|
|
// SAFETY: We just created the bundle, and the archetype is valid, since we are in it.
|
|
let Some(mut remover) = (unsafe {
|
|
BundleRemover::new_with_id(self.world, self.location.archetype_id, bundle_id, false)
|
|
}) else {
|
|
return self;
|
|
};
|
|
// SAFETY: The remover archetype came from the passed location and the removal can not fail.
|
|
let new_location = unsafe {
|
|
remover.remove(
|
|
self.entity,
|
|
self.location,
|
|
caller,
|
|
BundleRemover::empty_pre_remove,
|
|
)
|
|
}
|
|
.0;
|
|
|
|
self.location = new_location;
|
|
self.world.flush();
|
|
self.update_location();
|
|
self
|
|
}
|
|
|
|
/// Removes any components except those in the [`Bundle`] (and its Required Components) from the entity.
|
|
///
|
|
/// See [`EntityCommands::retain`](crate::system::EntityCommands::retain) for more details.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[track_caller]
|
|
pub fn retain<T: Bundle>(&mut self) -> &mut Self {
|
|
self.retain_with_caller::<T>(MaybeLocation::caller())
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn retain_with_caller<T: Bundle>(&mut self, caller: MaybeLocation) -> &mut Self {
|
|
self.assert_not_despawned();
|
|
let archetypes = &mut self.world.archetypes;
|
|
let storages = &mut self.world.storages;
|
|
// SAFETY: These come from the same world.
|
|
let mut registrator = unsafe {
|
|
ComponentsRegistrator::new(&mut self.world.components, &mut self.world.component_ids)
|
|
};
|
|
|
|
let retained_bundle = self
|
|
.world
|
|
.bundles
|
|
.register_info::<T>(&mut registrator, storages);
|
|
// SAFETY: `retained_bundle` exists as we just initialized it.
|
|
let retained_bundle_info = unsafe { self.world.bundles.get_unchecked(retained_bundle) };
|
|
let old_location = self.location;
|
|
let old_archetype = &mut archetypes[old_location.archetype_id];
|
|
|
|
// PERF: this could be stored in an Archetype Edge
|
|
let to_remove = &old_archetype
|
|
.components()
|
|
.filter(|c| !retained_bundle_info.contributed_components().contains(c))
|
|
.collect::<Vec<_>>();
|
|
let remove_bundle =
|
|
self.world
|
|
.bundles
|
|
.init_dynamic_info(&mut self.world.storages, ®istrator, to_remove);
|
|
|
|
// SAFETY: We just created the bundle, and the archetype is valid, since we are in it.
|
|
let Some(mut remover) = (unsafe {
|
|
BundleRemover::new_with_id(self.world, self.location.archetype_id, remove_bundle, false)
|
|
}) else {
|
|
return self;
|
|
};
|
|
// SAFETY: The remover archetype came from the passed location and the removal can not fail.
|
|
let new_location = unsafe {
|
|
remover.remove(
|
|
self.entity,
|
|
self.location,
|
|
caller,
|
|
BundleRemover::empty_pre_remove,
|
|
)
|
|
}
|
|
.0;
|
|
|
|
self.location = new_location;
|
|
self.world.flush();
|
|
self.update_location();
|
|
self
|
|
}
|
|
|
|
/// Removes a dynamic [`Component`] from the entity if it exists.
|
|
///
|
|
/// You should prefer to use the typed API [`EntityWorldMut::remove`] where possible.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// Panics if the provided [`ComponentId`] does not exist in the [`World`] or if the
|
|
/// entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[track_caller]
|
|
pub fn remove_by_id(&mut self, component_id: ComponentId) -> &mut Self {
|
|
self.remove_by_id_with_caller(component_id, MaybeLocation::caller())
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn remove_by_id_with_caller(
|
|
&mut self,
|
|
component_id: ComponentId,
|
|
caller: MaybeLocation,
|
|
) -> &mut Self {
|
|
self.assert_not_despawned();
|
|
let components = &mut self.world.components;
|
|
|
|
let bundle_id = self.world.bundles.init_component_info(
|
|
&mut self.world.storages,
|
|
components,
|
|
component_id,
|
|
);
|
|
|
|
// SAFETY: We just created the bundle, and the archetype is valid, since we are in it.
|
|
let Some(mut remover) = (unsafe {
|
|
BundleRemover::new_with_id(self.world, self.location.archetype_id, bundle_id, false)
|
|
}) else {
|
|
return self;
|
|
};
|
|
// SAFETY: The remover archetype came from the passed location and the removal can not fail.
|
|
let new_location = unsafe {
|
|
remover.remove(
|
|
self.entity,
|
|
self.location,
|
|
caller,
|
|
BundleRemover::empty_pre_remove,
|
|
)
|
|
}
|
|
.0;
|
|
|
|
self.location = new_location;
|
|
self.world.flush();
|
|
self.update_location();
|
|
self
|
|
}
|
|
|
|
/// Removes a dynamic bundle from the entity if it exists.
|
|
///
|
|
/// You should prefer to use the typed API [`EntityWorldMut::remove`] where possible.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// Panics if any of the provided [`ComponentId`]s do not exist in the [`World`] or if the
|
|
/// entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[track_caller]
|
|
pub fn remove_by_ids(&mut self, component_ids: &[ComponentId]) -> &mut Self {
|
|
self.assert_not_despawned();
|
|
let components = &mut self.world.components;
|
|
|
|
let bundle_id = self.world.bundles.init_dynamic_info(
|
|
&mut self.world.storages,
|
|
components,
|
|
component_ids,
|
|
);
|
|
|
|
// SAFETY: We just created the bundle, and the archetype is valid, since we are in it.
|
|
let Some(mut remover) = (unsafe {
|
|
BundleRemover::new_with_id(self.world, self.location.archetype_id, bundle_id, false)
|
|
}) else {
|
|
return self;
|
|
};
|
|
// SAFETY: The remover archetype came from the passed location and the removal can not fail.
|
|
let new_location = unsafe {
|
|
remover.remove(
|
|
self.entity,
|
|
self.location,
|
|
MaybeLocation::caller(),
|
|
BundleRemover::empty_pre_remove,
|
|
)
|
|
}
|
|
.0;
|
|
|
|
self.location = new_location;
|
|
self.world.flush();
|
|
self.update_location();
|
|
self
|
|
}
|
|
|
|
/// Removes all components associated with the entity.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[track_caller]
|
|
pub fn clear(&mut self) -> &mut Self {
|
|
self.clear_with_caller(MaybeLocation::caller())
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn clear_with_caller(&mut self, caller: MaybeLocation) -> &mut Self {
|
|
self.assert_not_despawned();
|
|
let component_ids: Vec<ComponentId> = self.archetype().components().collect();
|
|
let components = &mut self.world.components;
|
|
|
|
let bundle_id = self.world.bundles.init_dynamic_info(
|
|
&mut self.world.storages,
|
|
components,
|
|
component_ids.as_slice(),
|
|
);
|
|
|
|
// SAFETY: We just created the bundle, and the archetype is valid, since we are in it.
|
|
let Some(mut remover) = (unsafe {
|
|
BundleRemover::new_with_id(self.world, self.location.archetype_id, bundle_id, false)
|
|
}) else {
|
|
return self;
|
|
};
|
|
// SAFETY: The remover archetype came from the passed location and the removal can not fail.
|
|
let new_location = unsafe {
|
|
remover.remove(
|
|
self.entity,
|
|
self.location,
|
|
caller,
|
|
BundleRemover::empty_pre_remove,
|
|
)
|
|
}
|
|
.0;
|
|
|
|
self.location = new_location;
|
|
self.world.flush();
|
|
self.update_location();
|
|
self
|
|
}
|
|
|
|
/// Despawns the current entity.
|
|
///
|
|
/// See [`World::despawn`] for more details.
|
|
///
|
|
/// # Note
|
|
///
|
|
/// This will also despawn any [`Children`](crate::hierarchy::Children) entities, and any other [`RelationshipTarget`](crate::relationship::RelationshipTarget) that is configured
|
|
/// to despawn descendants. This results in "recursive despawn" behavior.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
#[track_caller]
|
|
pub fn despawn(self) {
|
|
self.despawn_with_caller(MaybeLocation::caller());
|
|
}
|
|
|
|
/// Despawns the provided entity and its descendants.
|
|
#[deprecated(
|
|
since = "0.16.0",
|
|
note = "Use entity.despawn(), which now automatically despawns recursively."
|
|
)]
|
|
pub fn despawn_recursive(self) {
|
|
self.despawn();
|
|
}
|
|
|
|
pub(crate) fn despawn_with_caller(self, caller: MaybeLocation) {
|
|
self.assert_not_despawned();
|
|
let world = self.world;
|
|
let archetype = &world.archetypes[self.location.archetype_id];
|
|
|
|
// SAFETY: Archetype cannot be mutably aliased by DeferredWorld
|
|
let (archetype, mut deferred_world) = unsafe {
|
|
let archetype: *const Archetype = archetype;
|
|
let world = world.as_unsafe_world_cell();
|
|
(&*archetype, world.into_deferred())
|
|
};
|
|
|
|
// SAFETY: All components in the archetype exist in world
|
|
unsafe {
|
|
if archetype.has_despawn_observer() {
|
|
deferred_world.trigger_observers(
|
|
ON_DESPAWN,
|
|
self.entity,
|
|
archetype.components(),
|
|
caller,
|
|
);
|
|
}
|
|
deferred_world.trigger_on_despawn(
|
|
archetype,
|
|
self.entity,
|
|
archetype.components(),
|
|
caller,
|
|
);
|
|
if archetype.has_replace_observer() {
|
|
deferred_world.trigger_observers(
|
|
ON_REPLACE,
|
|
self.entity,
|
|
archetype.components(),
|
|
caller,
|
|
);
|
|
}
|
|
deferred_world.trigger_on_replace(
|
|
archetype,
|
|
self.entity,
|
|
archetype.components(),
|
|
caller,
|
|
RelationshipHookMode::Run,
|
|
);
|
|
if archetype.has_remove_observer() {
|
|
deferred_world.trigger_observers(
|
|
ON_REMOVE,
|
|
self.entity,
|
|
archetype.components(),
|
|
caller,
|
|
);
|
|
}
|
|
deferred_world.trigger_on_remove(
|
|
archetype,
|
|
self.entity,
|
|
archetype.components(),
|
|
caller,
|
|
);
|
|
}
|
|
|
|
for component_id in archetype.components() {
|
|
world.removed_components.send(component_id, self.entity);
|
|
}
|
|
|
|
// Observers and on_remove hooks may reserve new entities, which
|
|
// requires a flush before Entities::free may be called.
|
|
world.flush_entities();
|
|
|
|
let location = world
|
|
.entities
|
|
.free(self.entity)
|
|
.expect("entity should exist at this point.");
|
|
let table_row;
|
|
let moved_entity;
|
|
|
|
{
|
|
let archetype = &mut world.archetypes[self.location.archetype_id];
|
|
let remove_result = archetype.swap_remove(location.archetype_row);
|
|
if let Some(swapped_entity) = remove_result.swapped_entity {
|
|
let swapped_location = world.entities.get(swapped_entity).unwrap();
|
|
// SAFETY: swapped_entity is valid and the swapped entity's components are
|
|
// moved to the new location immediately after.
|
|
unsafe {
|
|
world.entities.set(
|
|
swapped_entity.index(),
|
|
EntityLocation {
|
|
archetype_id: swapped_location.archetype_id,
|
|
archetype_row: location.archetype_row,
|
|
table_id: swapped_location.table_id,
|
|
table_row: swapped_location.table_row,
|
|
},
|
|
);
|
|
}
|
|
}
|
|
table_row = remove_result.table_row;
|
|
|
|
for component_id in archetype.sparse_set_components() {
|
|
// set must have existed for the component to be added.
|
|
let sparse_set = world.storages.sparse_sets.get_mut(component_id).unwrap();
|
|
sparse_set.remove(self.entity);
|
|
}
|
|
// SAFETY: table rows stored in archetypes always exist
|
|
moved_entity = unsafe {
|
|
world.storages.tables[archetype.table_id()].swap_remove_unchecked(table_row)
|
|
};
|
|
};
|
|
|
|
if let Some(moved_entity) = moved_entity {
|
|
let moved_location = world.entities.get(moved_entity).unwrap();
|
|
// SAFETY: `moved_entity` is valid and the provided `EntityLocation` accurately reflects
|
|
// the current location of the entity and its component data.
|
|
unsafe {
|
|
world.entities.set(
|
|
moved_entity.index(),
|
|
EntityLocation {
|
|
archetype_id: moved_location.archetype_id,
|
|
archetype_row: moved_location.archetype_row,
|
|
table_id: moved_location.table_id,
|
|
table_row,
|
|
},
|
|
);
|
|
}
|
|
world.archetypes[moved_location.archetype_id]
|
|
.set_entity_table_row(moved_location.archetype_row, table_row);
|
|
}
|
|
world.flush();
|
|
|
|
// SAFETY: No structural changes
|
|
unsafe {
|
|
world
|
|
.entities_mut()
|
|
.set_spawned_or_despawned_by(self.entity.index(), caller);
|
|
}
|
|
}
|
|
|
|
/// Ensures any commands triggered by the actions of Self are applied, equivalent to [`World::flush`]
|
|
pub fn flush(self) -> Entity {
|
|
self.world.flush();
|
|
self.entity
|
|
}
|
|
|
|
/// Gets read-only access to the world that the current entity belongs to.
|
|
#[inline]
|
|
pub fn world(&self) -> &World {
|
|
self.world
|
|
}
|
|
|
|
/// Returns this entity's world.
|
|
///
|
|
/// See [`EntityWorldMut::world_scope`] or [`EntityWorldMut::into_world_mut`] for a safe alternative.
|
|
///
|
|
/// # Safety
|
|
/// Caller must not modify the world in a way that changes the current entity's location
|
|
/// If the caller _does_ do something that could change the location, `self.update_location()`
|
|
/// must be called before using any other methods on this [`EntityWorldMut`].
|
|
#[inline]
|
|
pub unsafe fn world_mut(&mut self) -> &mut World {
|
|
self.world
|
|
}
|
|
|
|
/// Returns this entity's [`World`], consuming itself.
|
|
#[inline]
|
|
pub fn into_world_mut(self) -> &'w mut World {
|
|
self.world
|
|
}
|
|
|
|
/// Gives mutable access to this entity's [`World`] in a temporary scope.
|
|
/// This is a safe alternative to using [`EntityWorldMut::world_mut`].
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// #[derive(Resource, Default, Clone, Copy)]
|
|
/// struct R(u32);
|
|
///
|
|
/// # let mut world = World::new();
|
|
/// # world.init_resource::<R>();
|
|
/// # let mut entity = world.spawn_empty();
|
|
/// // This closure gives us temporary access to the world.
|
|
/// let new_r = entity.world_scope(|world: &mut World| {
|
|
/// // Mutate the world while we have access to it.
|
|
/// let mut r = world.resource_mut::<R>();
|
|
/// r.0 += 1;
|
|
///
|
|
/// // Return a value from the world before giving it back to the `EntityWorldMut`.
|
|
/// *r
|
|
/// });
|
|
/// # assert_eq!(new_r.0, 1);
|
|
/// ```
|
|
pub fn world_scope<U>(&mut self, f: impl FnOnce(&mut World) -> U) -> U {
|
|
struct Guard<'w, 'a> {
|
|
entity_mut: &'a mut EntityWorldMut<'w>,
|
|
}
|
|
|
|
impl Drop for Guard<'_, '_> {
|
|
#[inline]
|
|
fn drop(&mut self) {
|
|
self.entity_mut.update_location();
|
|
}
|
|
}
|
|
|
|
// When `guard` is dropped at the end of this scope,
|
|
// it will update the cached `EntityLocation` for this instance.
|
|
// This will run even in case the closure `f` unwinds.
|
|
let guard = Guard { entity_mut: self };
|
|
f(guard.entity_mut.world)
|
|
}
|
|
|
|
/// Updates the internal entity location to match the current location in the internal
|
|
/// [`World`].
|
|
///
|
|
/// This is *only* required when using the unsafe function [`EntityWorldMut::world_mut`],
|
|
/// which enables the location to change.
|
|
pub fn update_location(&mut self) {
|
|
self.location = self
|
|
.world
|
|
.entities()
|
|
.get(self.entity)
|
|
.unwrap_or(EntityLocation::INVALID);
|
|
}
|
|
|
|
/// Returns if the entity has been despawned.
|
|
///
|
|
/// Normally it shouldn't be needed to explicitly check if the entity has been despawned
|
|
/// between commands as this shouldn't happen. However, for some special cases where it
|
|
/// is known that a hook or an observer might despawn the entity while a [`EntityWorldMut`]
|
|
/// reference is still held, this method can be used to check if the entity is still alive
|
|
/// to avoid panicking when calling further methods.
|
|
#[inline]
|
|
pub fn is_despawned(&self) -> bool {
|
|
self.location.archetype_id == ArchetypeId::INVALID
|
|
}
|
|
|
|
/// Gets an Entry into the world for this entity and component for in-place manipulation.
|
|
///
|
|
/// The type parameter specifies which component to get.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)]
|
|
/// struct Comp(u32);
|
|
///
|
|
/// # let mut world = World::new();
|
|
/// let mut entity = world.spawn_empty();
|
|
/// entity.entry().or_insert_with(|| Comp(4));
|
|
/// # let entity_id = entity.id();
|
|
/// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 4);
|
|
///
|
|
/// # let mut entity = world.get_entity_mut(entity_id).unwrap();
|
|
/// entity.entry::<Comp>().and_modify(|mut c| c.0 += 1);
|
|
/// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 5);
|
|
/// ```
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
pub fn entry<'a, T: Component>(&'a mut self) -> Entry<'w, 'a, T> {
|
|
if self.contains::<T>() {
|
|
Entry::Occupied(OccupiedEntry {
|
|
entity_world: self,
|
|
_marker: PhantomData,
|
|
})
|
|
} else {
|
|
Entry::Vacant(VacantEntry {
|
|
entity_world: self,
|
|
_marker: PhantomData,
|
|
})
|
|
}
|
|
}
|
|
|
|
/// Triggers the given `event` for this entity, which will run any observers watching for it.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
pub fn trigger(&mut self, event: impl Event) -> &mut Self {
|
|
self.assert_not_despawned();
|
|
self.world.trigger_targets(event, self.entity);
|
|
self.world.flush();
|
|
self.update_location();
|
|
self
|
|
}
|
|
|
|
/// Creates an [`Observer`] listening for events of type `E` targeting this entity.
|
|
/// In order to trigger the callback the entity must also match the query when the event is fired.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
|
///
|
|
/// Panics if the given system is an exclusive system.
|
|
#[track_caller]
|
|
pub fn observe<E: Event, B: Bundle, M>(
|
|
&mut self,
|
|
observer: impl IntoObserverSystem<E, B, M>,
|
|
) -> &mut Self {
|
|
self.observe_with_caller(observer, MaybeLocation::caller())
|
|
}
|
|
|
|
pub(crate) fn observe_with_caller<E: Event, B: Bundle, M>(
|
|
&mut self,
|
|
observer: impl IntoObserverSystem<E, B, M>,
|
|
caller: MaybeLocation,
|
|
) -> &mut Self {
|
|
self.assert_not_despawned();
|
|
self.world
|
|
.spawn_with_caller(Observer::new(observer).with_entity(self.entity), caller);
|
|
self.world.flush();
|
|
self.update_location();
|
|
self
|
|
}
|
|
|
|
/// Clones parts of an entity (components, observers, etc.) onto another entity,
|
|
/// configured through [`EntityClonerBuilder`].
|
|
///
|
|
/// By default, the other entity will receive all the components of the original that implement
|
|
/// [`Clone`] or [`Reflect`](bevy_reflect::Reflect).
|
|
///
|
|
/// Configure through [`EntityClonerBuilder`] as follows:
|
|
/// ```
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// # #[derive(Component, Clone, PartialEq, Debug)]
|
|
/// # struct ComponentA;
|
|
/// # #[derive(Component, Clone, PartialEq, Debug)]
|
|
/// # struct ComponentB;
|
|
/// # let mut world = World::new();
|
|
/// # let entity = world.spawn((ComponentA, ComponentB)).id();
|
|
/// # let target = world.spawn_empty().id();
|
|
/// world.entity_mut(entity).clone_with(target, |builder| {
|
|
/// builder.deny::<ComponentB>();
|
|
/// });
|
|
/// # assert_eq!(world.get::<ComponentA>(target), Some(&ComponentA));
|
|
/// # assert_eq!(world.get::<ComponentB>(target), None);
|
|
/// ```
|
|
///
|
|
/// See [`EntityClonerBuilder`] for more options.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// - If this entity has been despawned while this `EntityWorldMut` is still alive.
|
|
/// - If the target entity does not exist.
|
|
pub fn clone_with(
|
|
&mut self,
|
|
target: Entity,
|
|
config: impl FnOnce(&mut EntityClonerBuilder) + Send + Sync + 'static,
|
|
) -> &mut Self {
|
|
self.assert_not_despawned();
|
|
|
|
let mut builder = EntityCloner::build(self.world);
|
|
config(&mut builder);
|
|
builder.clone_entity(self.entity, target);
|
|
|
|
self.world.flush();
|
|
self.update_location();
|
|
self
|
|
}
|
|
|
|
/// Spawns a clone of this entity and returns the [`Entity`] of the clone.
|
|
///
|
|
/// The clone will receive all the components of the original that implement
|
|
/// [`Clone`] or [`Reflect`](bevy_reflect::Reflect).
|
|
///
|
|
/// To configure cloning behavior (such as only cloning certain components),
|
|
/// use [`EntityWorldMut::clone_and_spawn_with`].
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If this entity has been despawned while this `EntityWorldMut` is still alive.
|
|
pub fn clone_and_spawn(&mut self) -> Entity {
|
|
self.clone_and_spawn_with(|_| {})
|
|
}
|
|
|
|
/// Spawns a clone of this entity and allows configuring cloning behavior
|
|
/// using [`EntityClonerBuilder`], returning the [`Entity`] of the clone.
|
|
///
|
|
/// By default, the clone will receive all the components of the original that implement
|
|
/// [`Clone`] or [`Reflect`](bevy_reflect::Reflect).
|
|
///
|
|
/// Configure through [`EntityClonerBuilder`] as follows:
|
|
/// ```
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// # #[derive(Component, Clone, PartialEq, Debug)]
|
|
/// # struct ComponentA;
|
|
/// # #[derive(Component, Clone, PartialEq, Debug)]
|
|
/// # struct ComponentB;
|
|
/// # let mut world = World::new();
|
|
/// # let entity = world.spawn((ComponentA, ComponentB)).id();
|
|
/// let entity_clone = world.entity_mut(entity).clone_and_spawn_with(|builder| {
|
|
/// builder.deny::<ComponentB>();
|
|
/// });
|
|
/// # assert_eq!(world.get::<ComponentA>(entity_clone), Some(&ComponentA));
|
|
/// # assert_eq!(world.get::<ComponentB>(entity_clone), None);
|
|
/// ```
|
|
///
|
|
/// See [`EntityClonerBuilder`] for more options.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If this entity has been despawned while this `EntityWorldMut` is still alive.
|
|
pub fn clone_and_spawn_with(
|
|
&mut self,
|
|
config: impl FnOnce(&mut EntityClonerBuilder) + Send + Sync + 'static,
|
|
) -> Entity {
|
|
self.assert_not_despawned();
|
|
|
|
let entity_clone = self.world.entities.reserve_entity();
|
|
self.world.flush();
|
|
|
|
let mut builder = EntityCloner::build(self.world);
|
|
config(&mut builder);
|
|
builder.clone_entity(self.entity, entity_clone);
|
|
|
|
self.world.flush();
|
|
self.update_location();
|
|
entity_clone
|
|
}
|
|
|
|
/// Clones the specified components of this entity and inserts them into another entity.
|
|
///
|
|
/// Components can only be cloned if they implement
|
|
/// [`Clone`] or [`Reflect`](bevy_reflect::Reflect).
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// - If this entity has been despawned while this `EntityWorldMut` is still alive.
|
|
/// - If the target entity does not exist.
|
|
pub fn clone_components<B: Bundle>(&mut self, target: Entity) -> &mut Self {
|
|
self.assert_not_despawned();
|
|
|
|
EntityCloner::build(self.world)
|
|
.deny_all()
|
|
.allow::<B>()
|
|
.clone_entity(self.entity, target);
|
|
|
|
self.world.flush();
|
|
self.update_location();
|
|
self
|
|
}
|
|
|
|
/// Clones the specified components of this entity and inserts them into another entity,
|
|
/// then removes the components from this entity.
|
|
///
|
|
/// Components can only be cloned if they implement
|
|
/// [`Clone`] or [`Reflect`](bevy_reflect::Reflect).
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// - If this entity has been despawned while this `EntityWorldMut` is still alive.
|
|
/// - If the target entity does not exist.
|
|
pub fn move_components<B: Bundle>(&mut self, target: Entity) -> &mut Self {
|
|
self.assert_not_despawned();
|
|
|
|
EntityCloner::build(self.world)
|
|
.deny_all()
|
|
.allow::<B>()
|
|
.move_components(true)
|
|
.clone_entity(self.entity, target);
|
|
|
|
self.world.flush();
|
|
self.update_location();
|
|
self
|
|
}
|
|
|
|
/// Returns the source code location from which this entity has last been spawned.
|
|
pub fn spawned_by(&self) -> MaybeLocation {
|
|
self.world()
|
|
.entities()
|
|
.entity_get_spawned_or_despawned_by(self.entity)
|
|
.map(|location| location.unwrap())
|
|
}
|
|
|
|
/// Reborrows this entity in a temporary scope.
|
|
/// This is useful for executing a function that requires a `EntityWorldMut`
|
|
/// but you do not want to move out the entity ownership.
|
|
pub fn reborrow_scope<U>(&mut self, f: impl FnOnce(EntityWorldMut) -> U) -> U {
|
|
let Self {
|
|
entity, location, ..
|
|
} = *self;
|
|
self.world_scope(move |world| {
|
|
f(EntityWorldMut {
|
|
world,
|
|
entity,
|
|
location,
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
/// A view into a single entity and component in a world, which may either be vacant or occupied.
|
|
///
|
|
/// This `enum` can only be constructed from the [`entry`] method on [`EntityWorldMut`].
|
|
///
|
|
/// [`entry`]: EntityWorldMut::entry
|
|
pub enum Entry<'w, 'a, T: Component> {
|
|
/// An occupied entry.
|
|
Occupied(OccupiedEntry<'w, 'a, T>),
|
|
/// A vacant entry.
|
|
Vacant(VacantEntry<'w, 'a, T>),
|
|
}
|
|
|
|
impl<'w, 'a, T: Component<Mutability = Mutable>> Entry<'w, 'a, T> {
|
|
/// Provides in-place mutable access to an occupied entry.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)]
|
|
/// struct Comp(u32);
|
|
///
|
|
/// # let mut world = World::new();
|
|
/// let mut entity = world.spawn(Comp(0));
|
|
///
|
|
/// entity.entry::<Comp>().and_modify(|mut c| c.0 += 1);
|
|
/// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 1);
|
|
/// ```
|
|
#[inline]
|
|
pub fn and_modify<F: FnOnce(Mut<'_, T>)>(self, f: F) -> Self {
|
|
match self {
|
|
Entry::Occupied(mut entry) => {
|
|
f(entry.get_mut());
|
|
Entry::Occupied(entry)
|
|
}
|
|
Entry::Vacant(entry) => Entry::Vacant(entry),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'w, 'a, T: Component> Entry<'w, 'a, T> {
|
|
/// Replaces the component of the entry, and returns an [`OccupiedEntry`].
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)]
|
|
/// struct Comp(u32);
|
|
///
|
|
/// # let mut world = World::new();
|
|
/// let mut entity = world.spawn_empty();
|
|
///
|
|
/// let entry = entity.entry().insert_entry(Comp(4));
|
|
/// assert_eq!(entry.get(), &Comp(4));
|
|
///
|
|
/// let entry = entity.entry().insert_entry(Comp(2));
|
|
/// assert_eq!(entry.get(), &Comp(2));
|
|
/// ```
|
|
#[inline]
|
|
pub fn insert_entry(self, component: T) -> OccupiedEntry<'w, 'a, T> {
|
|
match self {
|
|
Entry::Occupied(mut entry) => {
|
|
entry.insert(component);
|
|
entry
|
|
}
|
|
Entry::Vacant(entry) => entry.insert(component),
|
|
}
|
|
}
|
|
|
|
/// Ensures the entry has this component by inserting the given default if empty, and
|
|
/// returns a mutable reference to this component in the entry.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)]
|
|
/// struct Comp(u32);
|
|
///
|
|
/// # let mut world = World::new();
|
|
/// let mut entity = world.spawn_empty();
|
|
///
|
|
/// entity.entry().or_insert(Comp(4));
|
|
/// # let entity_id = entity.id();
|
|
/// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 4);
|
|
///
|
|
/// # let mut entity = world.get_entity_mut(entity_id).unwrap();
|
|
/// entity.entry().or_insert(Comp(15)).into_mut().0 *= 2;
|
|
/// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 8);
|
|
/// ```
|
|
#[inline]
|
|
pub fn or_insert(self, default: T) -> OccupiedEntry<'w, 'a, T> {
|
|
match self {
|
|
Entry::Occupied(entry) => entry,
|
|
Entry::Vacant(entry) => entry.insert(default),
|
|
}
|
|
}
|
|
|
|
/// Ensures the entry has this component by inserting the result of the default function if
|
|
/// empty, and returns a mutable reference to this component in the entry.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)]
|
|
/// struct Comp(u32);
|
|
///
|
|
/// # let mut world = World::new();
|
|
/// let mut entity = world.spawn_empty();
|
|
///
|
|
/// entity.entry().or_insert_with(|| Comp(4));
|
|
/// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 4);
|
|
/// ```
|
|
#[inline]
|
|
pub fn or_insert_with<F: FnOnce() -> T>(self, default: F) -> OccupiedEntry<'w, 'a, T> {
|
|
match self {
|
|
Entry::Occupied(entry) => entry,
|
|
Entry::Vacant(entry) => entry.insert(default()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'w, 'a, T: Component + Default> Entry<'w, 'a, T> {
|
|
/// Ensures the entry has this component by inserting the default value if empty, and
|
|
/// returns a mutable reference to this component in the entry.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)]
|
|
/// struct Comp(u32);
|
|
///
|
|
/// # let mut world = World::new();
|
|
/// let mut entity = world.spawn_empty();
|
|
///
|
|
/// entity.entry::<Comp>().or_default();
|
|
/// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 0);
|
|
/// ```
|
|
#[inline]
|
|
pub fn or_default(self) -> OccupiedEntry<'w, 'a, T> {
|
|
match self {
|
|
Entry::Occupied(entry) => entry,
|
|
Entry::Vacant(entry) => entry.insert(Default::default()),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// A view into an occupied entry in a [`EntityWorldMut`]. It is part of the [`Entry`] enum.
|
|
///
|
|
/// The contained entity must have the component type parameter if we have this struct.
|
|
pub struct OccupiedEntry<'w, 'a, T: Component> {
|
|
entity_world: &'a mut EntityWorldMut<'w>,
|
|
_marker: PhantomData<T>,
|
|
}
|
|
|
|
impl<'w, 'a, T: Component> OccupiedEntry<'w, 'a, T> {
|
|
/// Gets a reference to the component in the entry.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::{prelude::*, world::Entry};
|
|
/// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)]
|
|
/// struct Comp(u32);
|
|
///
|
|
/// # let mut world = World::new();
|
|
/// let mut entity = world.spawn(Comp(5));
|
|
///
|
|
/// if let Entry::Occupied(o) = entity.entry::<Comp>() {
|
|
/// assert_eq!(o.get().0, 5);
|
|
/// }
|
|
/// ```
|
|
#[inline]
|
|
pub fn get(&self) -> &T {
|
|
// This shouldn't panic because if we have an OccupiedEntry the component must exist.
|
|
self.entity_world.get::<T>().unwrap()
|
|
}
|
|
|
|
/// Replaces the component of the entry.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::{prelude::*, world::Entry};
|
|
/// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)]
|
|
/// struct Comp(u32);
|
|
///
|
|
/// # let mut world = World::new();
|
|
/// let mut entity = world.spawn(Comp(5));
|
|
///
|
|
/// if let Entry::Occupied(mut o) = entity.entry::<Comp>() {
|
|
/// o.insert(Comp(10));
|
|
/// }
|
|
///
|
|
/// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 10);
|
|
/// ```
|
|
#[inline]
|
|
pub fn insert(&mut self, component: T) {
|
|
self.entity_world.insert(component);
|
|
}
|
|
|
|
/// Removes the component from the entry and returns it.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::{prelude::*, world::Entry};
|
|
/// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)]
|
|
/// struct Comp(u32);
|
|
///
|
|
/// # let mut world = World::new();
|
|
/// let mut entity = world.spawn(Comp(5));
|
|
///
|
|
/// if let Entry::Occupied(o) = entity.entry::<Comp>() {
|
|
/// assert_eq!(o.take(), Comp(5));
|
|
/// }
|
|
///
|
|
/// assert_eq!(world.query::<&Comp>().iter(&world).len(), 0);
|
|
/// ```
|
|
#[inline]
|
|
pub fn take(self) -> T {
|
|
// This shouldn't panic because if we have an OccupiedEntry the component must exist.
|
|
self.entity_world.take().unwrap()
|
|
}
|
|
}
|
|
|
|
impl<'w, 'a, T: Component<Mutability = Mutable>> OccupiedEntry<'w, 'a, T> {
|
|
/// Gets a mutable reference to the component in the entry.
|
|
///
|
|
/// If you need a reference to the `OccupiedEntry` which may outlive the destruction of
|
|
/// the `Entry` value, see [`into_mut`].
|
|
///
|
|
/// [`into_mut`]: Self::into_mut
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::{prelude::*, world::Entry};
|
|
/// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)]
|
|
/// struct Comp(u32);
|
|
///
|
|
/// # let mut world = World::new();
|
|
/// let mut entity = world.spawn(Comp(5));
|
|
///
|
|
/// if let Entry::Occupied(mut o) = entity.entry::<Comp>() {
|
|
/// o.get_mut().0 += 10;
|
|
/// assert_eq!(o.get().0, 15);
|
|
///
|
|
/// // We can use the same Entry multiple times.
|
|
/// o.get_mut().0 += 2
|
|
/// }
|
|
///
|
|
/// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 17);
|
|
/// ```
|
|
#[inline]
|
|
pub fn get_mut(&mut self) -> Mut<'_, T> {
|
|
// This shouldn't panic because if we have an OccupiedEntry the component must exist.
|
|
self.entity_world.get_mut::<T>().unwrap()
|
|
}
|
|
|
|
/// Converts the `OccupiedEntry` into a mutable reference to the value in the entry with
|
|
/// a lifetime bound to the `EntityWorldMut`.
|
|
///
|
|
/// If you need multiple references to the `OccupiedEntry`, see [`get_mut`].
|
|
///
|
|
/// [`get_mut`]: Self::get_mut
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::{prelude::*, world::Entry};
|
|
/// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)]
|
|
/// struct Comp(u32);
|
|
///
|
|
/// # let mut world = World::new();
|
|
/// let mut entity = world.spawn(Comp(5));
|
|
///
|
|
/// if let Entry::Occupied(o) = entity.entry::<Comp>() {
|
|
/// o.into_mut().0 += 10;
|
|
/// }
|
|
///
|
|
/// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 15);
|
|
/// ```
|
|
#[inline]
|
|
pub fn into_mut(self) -> Mut<'a, T> {
|
|
// This shouldn't panic because if we have an OccupiedEntry the component must exist.
|
|
self.entity_world.get_mut().unwrap()
|
|
}
|
|
}
|
|
|
|
/// A view into a vacant entry in a [`EntityWorldMut`]. It is part of the [`Entry`] enum.
|
|
pub struct VacantEntry<'w, 'a, T: Component> {
|
|
entity_world: &'a mut EntityWorldMut<'w>,
|
|
_marker: PhantomData<T>,
|
|
}
|
|
|
|
impl<'w, 'a, T: Component> VacantEntry<'w, 'a, T> {
|
|
/// Inserts the component into the `VacantEntry` and returns an `OccupiedEntry`.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::{prelude::*, world::Entry};
|
|
/// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)]
|
|
/// struct Comp(u32);
|
|
///
|
|
/// # let mut world = World::new();
|
|
/// let mut entity = world.spawn_empty();
|
|
///
|
|
/// if let Entry::Vacant(v) = entity.entry::<Comp>() {
|
|
/// v.insert(Comp(10));
|
|
/// }
|
|
///
|
|
/// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 10);
|
|
/// ```
|
|
#[inline]
|
|
pub fn insert(self, component: T) -> OccupiedEntry<'w, 'a, T> {
|
|
self.entity_world.insert(component);
|
|
OccupiedEntry {
|
|
entity_world: self.entity_world,
|
|
_marker: PhantomData,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Provides read-only access to a single entity and some of its components defined by the contained [`Access`].
|
|
///
|
|
/// To define the access when used as a [`QueryData`](crate::query::QueryData),
|
|
/// use a [`QueryBuilder`](crate::query::QueryBuilder) or [`QueryParamBuilder`](crate::system::QueryParamBuilder).
|
|
/// The `FilteredEntityRef` must be the entire `QueryData`, and not nested inside a tuple with other data.
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::{prelude::*, world::FilteredEntityRef};
|
|
/// #
|
|
/// # #[derive(Component)]
|
|
/// # struct A;
|
|
/// #
|
|
/// # let mut world = World::new();
|
|
/// # world.spawn(A);
|
|
/// #
|
|
/// // This gives the `FilteredEntityRef` access to `&A`.
|
|
/// let mut query = QueryBuilder::<FilteredEntityRef>::new(&mut world)
|
|
/// .data::<&A>()
|
|
/// .build();
|
|
///
|
|
/// let filtered_entity: FilteredEntityRef = query.single(&mut world).unwrap();
|
|
/// let component: &A = filtered_entity.get().unwrap();
|
|
/// ```
|
|
#[derive(Clone)]
|
|
pub struct FilteredEntityRef<'w> {
|
|
entity: UnsafeEntityCell<'w>,
|
|
access: Access<ComponentId>,
|
|
}
|
|
|
|
impl<'w> FilteredEntityRef<'w> {
|
|
/// # Safety
|
|
/// - No `&mut World` can exist from the underlying `UnsafeWorldCell`
|
|
/// - If `access` takes read access to a component no mutable reference to that
|
|
/// component can exist at the same time as the returned [`FilteredEntityMut`]
|
|
/// - If `access` takes any access for a component `entity` must have that component.
|
|
#[inline]
|
|
pub(crate) unsafe fn new(entity: UnsafeEntityCell<'w>, access: Access<ComponentId>) -> Self {
|
|
Self { entity, access }
|
|
}
|
|
|
|
/// Returns the [ID](Entity) of the current entity.
|
|
#[inline]
|
|
#[must_use = "Omit the .id() call if you do not need to store the `Entity` identifier."]
|
|
pub fn id(&self) -> Entity {
|
|
self.entity.id()
|
|
}
|
|
|
|
/// Gets metadata indicating the location where the current entity is stored.
|
|
#[inline]
|
|
pub fn location(&self) -> EntityLocation {
|
|
self.entity.location()
|
|
}
|
|
|
|
/// Returns the archetype that the current entity belongs to.
|
|
#[inline]
|
|
pub fn archetype(&self) -> &Archetype {
|
|
self.entity.archetype()
|
|
}
|
|
|
|
/// Returns a reference to the underlying [`Access`].
|
|
#[inline]
|
|
pub fn access(&self) -> &Access<ComponentId> {
|
|
&self.access
|
|
}
|
|
|
|
/// 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.entity.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.entity.contains_type_id(type_id)
|
|
}
|
|
|
|
/// Gets access to the component of type `T` for the current entity.
|
|
/// Returns `None` if the entity does not have a component of type `T`.
|
|
#[inline]
|
|
pub fn get<T: Component>(&self) -> Option<&'w T> {
|
|
let id = self.entity.world().components().get_id(TypeId::of::<T>())?;
|
|
self.access
|
|
.has_component_read(id)
|
|
// SAFETY: We have read access
|
|
.then(|| unsafe { self.entity.get() })
|
|
.flatten()
|
|
}
|
|
|
|
/// 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<'w, T>> {
|
|
let id = self.entity.world().components().get_id(TypeId::of::<T>())?;
|
|
self.access
|
|
.has_component_read(id)
|
|
// SAFETY: We have read access
|
|
.then(|| unsafe { self.entity.get_ref() })
|
|
.flatten()
|
|
}
|
|
|
|
/// 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> {
|
|
let id = self.entity.world().components().get_id(TypeId::of::<T>())?;
|
|
self.access
|
|
.has_component_read(id)
|
|
// SAFETY: We have read access
|
|
.then(|| unsafe { self.entity.get_change_ticks::<T>() })
|
|
.flatten()
|
|
}
|
|
|
|
/// 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 [`Self::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.access
|
|
.has_component_read(component_id)
|
|
// SAFETY: We have read access
|
|
.then(|| unsafe { self.entity.get_change_ticks_by_id(component_id) })
|
|
.flatten()
|
|
}
|
|
|
|
/// Gets the component of the given [`ComponentId`] from the entity.
|
|
///
|
|
/// **You should prefer to use the typed API [`Self::get`] where possible and only
|
|
/// use this in cases where the actual component types are not known at
|
|
/// compile time.**
|
|
///
|
|
/// Unlike [`FilteredEntityRef::get`], this returns a raw pointer to the component,
|
|
/// which is only valid while the [`FilteredEntityRef`] is alive.
|
|
#[inline]
|
|
pub fn get_by_id(&self, component_id: ComponentId) -> Option<Ptr<'w>> {
|
|
self.access
|
|
.has_component_read(component_id)
|
|
// SAFETY: We have read access
|
|
.then(|| unsafe { self.entity.get_by_id(component_id) })
|
|
.flatten()
|
|
}
|
|
|
|
/// Returns the source code location from which this entity has been spawned.
|
|
pub fn spawned_by(&self) -> MaybeLocation {
|
|
self.entity.spawned_by()
|
|
}
|
|
}
|
|
|
|
impl<'w> From<FilteredEntityMut<'w>> for FilteredEntityRef<'w> {
|
|
#[inline]
|
|
fn from(entity: FilteredEntityMut<'w>) -> Self {
|
|
// SAFETY:
|
|
// - `FilteredEntityMut` guarantees exclusive access to all components in the new `FilteredEntityRef`.
|
|
unsafe { FilteredEntityRef::new(entity.entity, entity.access) }
|
|
}
|
|
}
|
|
|
|
impl<'a> From<&'a FilteredEntityMut<'_>> for FilteredEntityRef<'a> {
|
|
#[inline]
|
|
fn from(entity: &'a FilteredEntityMut<'_>) -> Self {
|
|
// SAFETY:
|
|
// - `FilteredEntityMut` guarantees exclusive access to all components in the new `FilteredEntityRef`.
|
|
unsafe { FilteredEntityRef::new(entity.entity, entity.access.clone()) }
|
|
}
|
|
}
|
|
|
|
impl<'a> From<EntityRef<'a>> for FilteredEntityRef<'a> {
|
|
fn from(entity: EntityRef<'a>) -> Self {
|
|
// SAFETY:
|
|
// - `EntityRef` guarantees exclusive access to all components in the new `FilteredEntityRef`.
|
|
unsafe {
|
|
let mut access = Access::default();
|
|
access.read_all();
|
|
FilteredEntityRef::new(entity.cell, access)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> From<&'a EntityRef<'_>> for FilteredEntityRef<'a> {
|
|
fn from(entity: &'a EntityRef<'_>) -> Self {
|
|
// SAFETY:
|
|
// - `EntityRef` guarantees exclusive access to all components in the new `FilteredEntityRef`.
|
|
unsafe {
|
|
let mut access = Access::default();
|
|
access.read_all();
|
|
FilteredEntityRef::new(entity.cell, access)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> From<EntityMut<'a>> for FilteredEntityRef<'a> {
|
|
fn from(entity: EntityMut<'a>) -> Self {
|
|
// SAFETY:
|
|
// - `EntityMut` guarantees exclusive access to all components in the new `FilteredEntityRef`.
|
|
unsafe {
|
|
let mut access = Access::default();
|
|
access.read_all();
|
|
FilteredEntityRef::new(entity.cell, access)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> From<&'a EntityMut<'_>> for FilteredEntityRef<'a> {
|
|
fn from(entity: &'a EntityMut<'_>) -> Self {
|
|
// SAFETY:
|
|
// - `EntityMut` guarantees exclusive access to all components in the new `FilteredEntityRef`.
|
|
unsafe {
|
|
let mut access = Access::default();
|
|
access.read_all();
|
|
FilteredEntityRef::new(entity.cell, access)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> From<EntityWorldMut<'a>> for FilteredEntityRef<'a> {
|
|
fn from(entity: EntityWorldMut<'a>) -> Self {
|
|
// SAFETY:
|
|
// - `EntityWorldMut` guarantees exclusive access to the entire world.
|
|
unsafe {
|
|
let mut access = Access::default();
|
|
access.read_all();
|
|
FilteredEntityRef::new(entity.into_unsafe_entity_cell(), access)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> From<&'a EntityWorldMut<'_>> for FilteredEntityRef<'a> {
|
|
fn from(entity: &'a EntityWorldMut<'_>) -> Self {
|
|
// SAFETY:
|
|
// - `EntityWorldMut` guarantees exclusive access to the entire world.
|
|
unsafe {
|
|
let mut access = Access::default();
|
|
access.read_all();
|
|
FilteredEntityRef::new(entity.as_unsafe_entity_cell_readonly(), access)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, B: Bundle> From<&'a EntityRefExcept<'_, B>> for FilteredEntityRef<'a> {
|
|
fn from(value: &'a EntityRefExcept<'_, B>) -> Self {
|
|
// SAFETY:
|
|
// - The FilteredEntityRef has the same component access as the given EntityRefExcept.
|
|
unsafe {
|
|
let mut access = Access::default();
|
|
access.read_all();
|
|
let components = value.entity.world().components();
|
|
B::get_component_ids(components, &mut |maybe_id| {
|
|
if let Some(id) = maybe_id {
|
|
access.remove_component_read(id);
|
|
}
|
|
});
|
|
FilteredEntityRef::new(value.entity, access)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PartialEq for FilteredEntityRef<'_> {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.entity() == other.entity()
|
|
}
|
|
}
|
|
|
|
impl Eq for FilteredEntityRef<'_> {}
|
|
|
|
impl PartialOrd for FilteredEntityRef<'_> {
|
|
/// [`FilteredEntityRef`]'s comparison trait implementations match the underlying [`Entity`],
|
|
/// and cannot discern between different worlds.
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
Some(self.cmp(other))
|
|
}
|
|
}
|
|
|
|
impl Ord for FilteredEntityRef<'_> {
|
|
fn cmp(&self, other: &Self) -> Ordering {
|
|
self.entity().cmp(&other.entity())
|
|
}
|
|
}
|
|
|
|
impl Hash for FilteredEntityRef<'_> {
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
self.entity().hash(state);
|
|
}
|
|
}
|
|
|
|
impl ContainsEntity for FilteredEntityRef<'_> {
|
|
fn entity(&self) -> Entity {
|
|
self.id()
|
|
}
|
|
}
|
|
|
|
// SAFETY: This type represents one Entity. We implement the comparison traits based on that Entity.
|
|
unsafe impl EntityEquivalent for FilteredEntityRef<'_> {}
|
|
|
|
/// Provides mutable access to a single entity and some of its components defined by the contained [`Access`].
|
|
///
|
|
/// To define the access when used as a [`QueryData`](crate::query::QueryData),
|
|
/// use a [`QueryBuilder`](crate::query::QueryBuilder) or [`QueryParamBuilder`](crate::system::QueryParamBuilder).
|
|
/// The `FilteredEntityMut` must be the entire `QueryData`, and not nested inside a tuple with other data.
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::{prelude::*, world::FilteredEntityMut};
|
|
/// #
|
|
/// # #[derive(Component)]
|
|
/// # struct A;
|
|
/// #
|
|
/// # let mut world = World::new();
|
|
/// # world.spawn(A);
|
|
/// #
|
|
/// // This gives the `FilteredEntityMut` access to `&mut A`.
|
|
/// let mut query = QueryBuilder::<FilteredEntityMut>::new(&mut world)
|
|
/// .data::<&mut A>()
|
|
/// .build();
|
|
///
|
|
/// let mut filtered_entity: FilteredEntityMut = query.single_mut(&mut world).unwrap();
|
|
/// let component: Mut<A> = filtered_entity.get_mut().unwrap();
|
|
/// ```
|
|
pub struct FilteredEntityMut<'w> {
|
|
entity: UnsafeEntityCell<'w>,
|
|
access: Access<ComponentId>,
|
|
}
|
|
|
|
impl<'w> FilteredEntityMut<'w> {
|
|
/// # Safety
|
|
/// - No `&mut World` can exist from the underlying `UnsafeWorldCell`
|
|
/// - If `access` takes read access to a component no mutable reference to that
|
|
/// component can exist at the same time as the returned [`FilteredEntityMut`]
|
|
/// - If `access` takes write access to a component, no reference to that component
|
|
/// may exist at the same time as the returned [`FilteredEntityMut`]
|
|
/// - If `access` takes any access for a component `entity` must have that component.
|
|
#[inline]
|
|
pub(crate) unsafe fn new(entity: UnsafeEntityCell<'w>, access: Access<ComponentId>) -> Self {
|
|
Self { entity, access }
|
|
}
|
|
|
|
/// Returns a new instance with a shorter lifetime.
|
|
/// This is useful if you have `&mut FilteredEntityMut`, but you need `FilteredEntityMut`.
|
|
pub fn reborrow(&mut self) -> FilteredEntityMut<'_> {
|
|
// SAFETY: We have exclusive access to the entire entity and its components.
|
|
unsafe { Self::new(self.entity, self.access.clone()) }
|
|
}
|
|
|
|
/// Gets read-only access to all of the entity's components.
|
|
#[inline]
|
|
pub fn as_readonly(&self) -> FilteredEntityRef<'_> {
|
|
FilteredEntityRef::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.entity.id()
|
|
}
|
|
|
|
/// Gets metadata indicating the location where the current entity is stored.
|
|
#[inline]
|
|
pub fn location(&self) -> EntityLocation {
|
|
self.entity.location()
|
|
}
|
|
|
|
/// Returns the archetype that the current entity belongs to.
|
|
#[inline]
|
|
pub fn archetype(&self) -> &Archetype {
|
|
self.entity.archetype()
|
|
}
|
|
|
|
/// Returns a reference to the underlying [`Access`].
|
|
#[inline]
|
|
pub fn access(&self) -> &Access<ComponentId> {
|
|
&self.access
|
|
}
|
|
|
|
/// 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.entity.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.entity.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<Mutability = Mutable>>(&mut self) -> Option<Mut<'_, T>> {
|
|
let id = self.entity.world().components().get_id(TypeId::of::<T>())?;
|
|
self.access
|
|
.has_component_write(id)
|
|
// SAFETY: We have write access
|
|
.then(|| unsafe { self.entity.get_mut() })
|
|
.flatten()
|
|
}
|
|
|
|
/// Consumes self and gets mutable access to the component of type `T`
|
|
/// with the world `'w` lifetime for the current entity.
|
|
/// Returns `None` if the entity does not have a component of type `T`.
|
|
#[inline]
|
|
pub fn into_mut<T: Component<Mutability = Mutable>>(self) -> Option<Mut<'w, T>> {
|
|
// SAFETY:
|
|
// - We have write access
|
|
// - The bound `T: Component<Mutability = Mutable>` ensures the component is mutable
|
|
unsafe { self.into_mut_assume_mutable() }
|
|
}
|
|
|
|
/// Consumes self and gets mutable access to the component of type `T`
|
|
/// with the world `'w` lifetime for the current entity.
|
|
/// Returns `None` if the entity does not have a component of type `T`.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// - `T` must be a mutable component
|
|
#[inline]
|
|
pub unsafe fn into_mut_assume_mutable<T: Component>(self) -> Option<Mut<'w, T>> {
|
|
let id = self.entity.world().components().get_id(TypeId::of::<T>())?;
|
|
self.access
|
|
.has_component_write(id)
|
|
// SAFETY:
|
|
// - We have write access
|
|
// - Caller ensures `T` is a mutable component
|
|
.then(|| unsafe { self.entity.get_mut_assume_mutable() })
|
|
.flatten()
|
|
}
|
|
|
|
/// 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 [`Self::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 [`Self::get`] where possible and only
|
|
/// use this in cases where the actual component types are not known at
|
|
/// compile time.**
|
|
///
|
|
/// Unlike [`FilteredEntityMut::get`], this returns a raw pointer to the component,
|
|
/// which is only valid while the [`FilteredEntityMut`] 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 [`Self::get_mut`] where possible and only
|
|
/// use this in cases where the actual component types are not known at
|
|
/// compile time.**
|
|
///
|
|
/// Unlike [`FilteredEntityMut::get_mut`], this returns a raw pointer to the component,
|
|
/// which is only valid while the [`FilteredEntityMut`] is alive.
|
|
#[inline]
|
|
pub fn get_mut_by_id(&mut self, component_id: ComponentId) -> Option<MutUntyped<'_>> {
|
|
self.access
|
|
.has_component_write(component_id)
|
|
// SAFETY: We have write access
|
|
.then(|| unsafe { self.entity.get_mut_by_id(component_id).ok() })
|
|
.flatten()
|
|
}
|
|
|
|
/// Returns the source code location from which this entity has last been spawned.
|
|
pub fn spawned_by(&self) -> MaybeLocation {
|
|
self.entity.spawned_by()
|
|
}
|
|
}
|
|
|
|
impl<'a> From<EntityMut<'a>> for FilteredEntityMut<'a> {
|
|
fn from(entity: EntityMut<'a>) -> Self {
|
|
// SAFETY:
|
|
// - `EntityMut` guarantees exclusive access to all components in the new `FilteredEntityMut`.
|
|
unsafe {
|
|
let mut access = Access::default();
|
|
access.read_all();
|
|
access.write_all();
|
|
FilteredEntityMut::new(entity.cell, access)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> From<&'a mut EntityMut<'_>> for FilteredEntityMut<'a> {
|
|
fn from(entity: &'a mut EntityMut<'_>) -> Self {
|
|
// SAFETY:
|
|
// - `EntityMut` guarantees exclusive access to all components in the new `FilteredEntityMut`.
|
|
unsafe {
|
|
let mut access = Access::default();
|
|
access.read_all();
|
|
access.write_all();
|
|
FilteredEntityMut::new(entity.cell, access)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> From<EntityWorldMut<'a>> for FilteredEntityMut<'a> {
|
|
fn from(entity: EntityWorldMut<'a>) -> Self {
|
|
// SAFETY:
|
|
// - `EntityWorldMut` guarantees exclusive access to the entire world.
|
|
unsafe {
|
|
let mut access = Access::default();
|
|
access.read_all();
|
|
access.write_all();
|
|
FilteredEntityMut::new(entity.into_unsafe_entity_cell(), access)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> From<&'a mut EntityWorldMut<'_>> for FilteredEntityMut<'a> {
|
|
fn from(entity: &'a mut EntityWorldMut<'_>) -> Self {
|
|
// SAFETY:
|
|
// - `EntityWorldMut` guarantees exclusive access to the entire world.
|
|
unsafe {
|
|
let mut access = Access::default();
|
|
access.read_all();
|
|
access.write_all();
|
|
FilteredEntityMut::new(entity.as_unsafe_entity_cell(), access)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, B: Bundle> From<&'a EntityMutExcept<'_, B>> for FilteredEntityMut<'a> {
|
|
fn from(value: &'a EntityMutExcept<'_, B>) -> Self {
|
|
// SAFETY:
|
|
// - The FilteredEntityMut has the same component access as the given EntityMutExcept.
|
|
unsafe {
|
|
let mut access = Access::default();
|
|
access.write_all();
|
|
let components = value.entity.world().components();
|
|
B::get_component_ids(components, &mut |maybe_id| {
|
|
if let Some(id) = maybe_id {
|
|
access.remove_component_read(id);
|
|
}
|
|
});
|
|
FilteredEntityMut::new(value.entity, access)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PartialEq for FilteredEntityMut<'_> {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.entity() == other.entity()
|
|
}
|
|
}
|
|
|
|
impl Eq for FilteredEntityMut<'_> {}
|
|
|
|
impl PartialOrd for FilteredEntityMut<'_> {
|
|
/// [`FilteredEntityMut`]'s comparison trait implementations match the underlying [`Entity`],
|
|
/// and cannot discern between different worlds.
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
Some(self.cmp(other))
|
|
}
|
|
}
|
|
|
|
impl Ord for FilteredEntityMut<'_> {
|
|
fn cmp(&self, other: &Self) -> Ordering {
|
|
self.entity().cmp(&other.entity())
|
|
}
|
|
}
|
|
|
|
impl Hash for FilteredEntityMut<'_> {
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
self.entity().hash(state);
|
|
}
|
|
}
|
|
|
|
impl ContainsEntity for FilteredEntityMut<'_> {
|
|
fn entity(&self) -> Entity {
|
|
self.id()
|
|
}
|
|
}
|
|
|
|
// SAFETY: This type represents one Entity. We implement the comparison traits based on that Entity.
|
|
unsafe impl EntityEquivalent for FilteredEntityMut<'_> {}
|
|
|
|
/// Error type returned by [`TryFrom`] conversions from filtered entity types
|
|
/// ([`FilteredEntityRef`]/[`FilteredEntityMut`]) to full-access entity types
|
|
/// ([`EntityRef`]/[`EntityMut`]).
|
|
#[derive(Error, Debug)]
|
|
pub enum TryFromFilteredError {
|
|
/// Error indicating that the filtered entity does not have read access to
|
|
/// all components.
|
|
#[error("Conversion failed, filtered entity ref does not have read access to all components")]
|
|
MissingReadAllAccess,
|
|
/// Error indicating that the filtered entity does not have write access to
|
|
/// all components.
|
|
#[error("Conversion failed, filtered entity ref does not have write access to all components")]
|
|
MissingWriteAllAccess,
|
|
}
|
|
|
|
/// Provides read-only access to a single entity and all its components, save
|
|
/// for an explicitly-enumerated set.
|
|
pub struct EntityRefExcept<'w, B>
|
|
where
|
|
B: Bundle,
|
|
{
|
|
entity: UnsafeEntityCell<'w>,
|
|
phantom: PhantomData<B>,
|
|
}
|
|
|
|
impl<'w, B> EntityRefExcept<'w, B>
|
|
where
|
|
B: Bundle,
|
|
{
|
|
/// # Safety
|
|
/// Other users of `UnsafeEntityCell` must only have mutable access to the components in `B`.
|
|
pub(crate) unsafe fn new(entity: UnsafeEntityCell<'w>) -> Self {
|
|
Self {
|
|
entity,
|
|
phantom: PhantomData,
|
|
}
|
|
}
|
|
|
|
/// Returns the [ID](Entity) of the current entity.
|
|
#[inline]
|
|
#[must_use = "Omit the .id() call if you do not need to store the `Entity` identifier."]
|
|
pub fn id(&self) -> Entity {
|
|
self.entity.id()
|
|
}
|
|
|
|
/// Gets access to the component of type `C` for the current entity. Returns
|
|
/// `None` if the component doesn't have a component of that type or if the
|
|
/// type is one of the excluded components.
|
|
#[inline]
|
|
pub fn get<C>(&self) -> Option<&'w C>
|
|
where
|
|
C: Component,
|
|
{
|
|
let components = self.entity.world().components();
|
|
let id = components.component_id::<C>()?;
|
|
if bundle_contains_component::<B>(components, id) {
|
|
None
|
|
} else {
|
|
// SAFETY: We have read access for all components that weren't
|
|
// covered by the `contains` check above.
|
|
unsafe { self.entity.get() }
|
|
}
|
|
}
|
|
|
|
/// Gets access to the component of type `C` for the current entity,
|
|
/// including change detection information. Returns `None` if the component
|
|
/// doesn't have a component of that type or if the type is one of the
|
|
/// excluded components.
|
|
#[inline]
|
|
pub fn get_ref<C>(&self) -> Option<Ref<'w, C>>
|
|
where
|
|
C: Component,
|
|
{
|
|
let components = self.entity.world().components();
|
|
let id = components.component_id::<C>()?;
|
|
if bundle_contains_component::<B>(components, id) {
|
|
None
|
|
} else {
|
|
// SAFETY: We have read access for all components that weren't
|
|
// covered by the `contains` check above.
|
|
unsafe { self.entity.get_ref() }
|
|
}
|
|
}
|
|
|
|
/// Returns the source code location from which this entity has been spawned.
|
|
pub fn spawned_by(&self) -> MaybeLocation {
|
|
self.entity.spawned_by()
|
|
}
|
|
|
|
/// Gets the component of the given [`ComponentId`] from the entity.
|
|
///
|
|
/// **You should prefer to use the typed API [`Self::get`] where possible and only
|
|
/// use this in cases where the actual component types are not known at
|
|
/// compile time.**
|
|
///
|
|
/// Unlike [`EntityRefExcept::get`], this returns a raw pointer to the component,
|
|
/// which is only valid while the [`EntityRefExcept`] is alive.
|
|
#[inline]
|
|
pub fn get_by_id(&self, component_id: ComponentId) -> Option<Ptr<'w>> {
|
|
let components = self.entity.world().components();
|
|
(!bundle_contains_component::<B>(components, component_id))
|
|
.then(|| {
|
|
// SAFETY: We have read access for this component
|
|
unsafe { self.entity.get_by_id(component_id) }
|
|
})
|
|
.flatten()
|
|
}
|
|
|
|
/// 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.entity.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.entity.contains_type_id(type_id)
|
|
}
|
|
|
|
/// 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> {
|
|
let component_id = self.entity.world().components().get_id(TypeId::of::<T>())?;
|
|
let components = self.entity.world().components();
|
|
(!bundle_contains_component::<B>(components, component_id))
|
|
.then(|| {
|
|
// SAFETY: We have read access
|
|
unsafe { self.entity.get_change_ticks::<T>() }
|
|
})
|
|
.flatten()
|
|
}
|
|
|
|
/// 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 [`Self::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> {
|
|
let components = self.entity.world().components();
|
|
(!bundle_contains_component::<B>(components, component_id))
|
|
.then(|| {
|
|
// SAFETY: We have read access
|
|
unsafe { self.entity.get_change_ticks_by_id(component_id) }
|
|
})
|
|
.flatten()
|
|
}
|
|
}
|
|
|
|
impl<'a, B> From<&'a EntityMutExcept<'_, B>> for EntityRefExcept<'a, B>
|
|
where
|
|
B: Bundle,
|
|
{
|
|
fn from(entity: &'a EntityMutExcept<'_, B>) -> Self {
|
|
// SAFETY: All accesses that `EntityRefExcept` provides are also
|
|
// accesses that `EntityMutExcept` provides.
|
|
unsafe { EntityRefExcept::new(entity.entity) }
|
|
}
|
|
}
|
|
|
|
impl<B: Bundle> Clone for EntityRefExcept<'_, B> {
|
|
fn clone(&self) -> Self {
|
|
*self
|
|
}
|
|
}
|
|
|
|
impl<B: Bundle> Copy for EntityRefExcept<'_, B> {}
|
|
|
|
impl<B: Bundle> PartialEq for EntityRefExcept<'_, B> {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.entity() == other.entity()
|
|
}
|
|
}
|
|
|
|
impl<B: Bundle> Eq for EntityRefExcept<'_, B> {}
|
|
|
|
impl<B: Bundle> PartialOrd for EntityRefExcept<'_, B> {
|
|
/// [`EntityRefExcept`]'s comparison trait implementations match the underlying [`Entity`],
|
|
/// and cannot discern between different worlds.
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
Some(self.cmp(other))
|
|
}
|
|
}
|
|
|
|
impl<B: Bundle> Ord for EntityRefExcept<'_, B> {
|
|
fn cmp(&self, other: &Self) -> Ordering {
|
|
self.entity().cmp(&other.entity())
|
|
}
|
|
}
|
|
|
|
impl<B: Bundle> Hash for EntityRefExcept<'_, B> {
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
self.entity().hash(state);
|
|
}
|
|
}
|
|
|
|
impl<B: Bundle> ContainsEntity for EntityRefExcept<'_, B> {
|
|
fn entity(&self) -> Entity {
|
|
self.id()
|
|
}
|
|
}
|
|
|
|
// SAFETY: This type represents one Entity. We implement the comparison traits based on that Entity.
|
|
unsafe impl<B: Bundle> EntityEquivalent for EntityRefExcept<'_, B> {}
|
|
|
|
/// Provides mutable access to all components of an entity, with the exception
|
|
/// of an explicit set.
|
|
///
|
|
/// This is a rather niche type that should only be used if you need access to
|
|
/// *all* components of an entity, while still allowing you to consult other
|
|
/// queries that might match entities that this query also matches. If you don't
|
|
/// need access to all components, prefer a standard query with a
|
|
/// [`crate::query::Without`] filter.
|
|
pub struct EntityMutExcept<'w, B>
|
|
where
|
|
B: Bundle,
|
|
{
|
|
entity: UnsafeEntityCell<'w>,
|
|
phantom: PhantomData<B>,
|
|
}
|
|
|
|
impl<'w, B> EntityMutExcept<'w, B>
|
|
where
|
|
B: Bundle,
|
|
{
|
|
/// # Safety
|
|
/// Other users of `UnsafeEntityCell` must not have access to any components not in `B`.
|
|
pub(crate) unsafe fn new(entity: UnsafeEntityCell<'w>) -> Self {
|
|
Self {
|
|
entity,
|
|
phantom: PhantomData,
|
|
}
|
|
}
|
|
|
|
/// Returns the [ID](Entity) of the current entity.
|
|
#[inline]
|
|
#[must_use = "Omit the .id() call if you do not need to store the `Entity` identifier."]
|
|
pub fn id(&self) -> Entity {
|
|
self.entity.id()
|
|
}
|
|
|
|
/// Returns a new instance with a shorter lifetime.
|
|
///
|
|
/// This is useful if you have `&mut EntityMutExcept`, but you need
|
|
/// `EntityMutExcept`.
|
|
pub fn reborrow(&mut self) -> EntityMutExcept<'_, B> {
|
|
// SAFETY: We have exclusive access to the entire entity and the
|
|
// applicable components.
|
|
unsafe { Self::new(self.entity) }
|
|
}
|
|
|
|
/// Gets read-only access to all of the entity's components, except for the
|
|
/// ones in `CL`.
|
|
#[inline]
|
|
pub fn as_readonly(&self) -> EntityRefExcept<'_, B> {
|
|
EntityRefExcept::from(self)
|
|
}
|
|
|
|
/// Gets access to the component of type `C` for the current entity. Returns
|
|
/// `None` if the component doesn't have a component of that type or if the
|
|
/// type is one of the excluded components.
|
|
#[inline]
|
|
pub fn get<C>(&self) -> Option<&'_ C>
|
|
where
|
|
C: Component,
|
|
{
|
|
self.as_readonly().get()
|
|
}
|
|
|
|
/// Gets access to the component of type `C` for the current entity,
|
|
/// including change detection information. Returns `None` if the component
|
|
/// doesn't have a component of that type or if the type is one of the
|
|
/// excluded components.
|
|
#[inline]
|
|
pub fn get_ref<C>(&self) -> Option<Ref<'_, C>>
|
|
where
|
|
C: Component,
|
|
{
|
|
self.as_readonly().get_ref()
|
|
}
|
|
|
|
/// Gets mutable access to the component of type `C` for the current entity.
|
|
/// Returns `None` if the component doesn't have a component of that type or
|
|
/// if the type is one of the excluded components.
|
|
#[inline]
|
|
pub fn get_mut<C>(&mut self) -> Option<Mut<'_, C>>
|
|
where
|
|
C: Component<Mutability = Mutable>,
|
|
{
|
|
let components = self.entity.world().components();
|
|
let id = components.component_id::<C>()?;
|
|
if bundle_contains_component::<B>(components, id) {
|
|
None
|
|
} else {
|
|
// SAFETY: We have write access for all components that weren't
|
|
// covered by the `contains` check above.
|
|
unsafe { self.entity.get_mut() }
|
|
}
|
|
}
|
|
|
|
/// Returns the source code location from which this entity has been spawned.
|
|
pub fn spawned_by(&self) -> MaybeLocation {
|
|
self.entity.spawned_by()
|
|
}
|
|
|
|
/// 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.entity.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.entity.contains_type_id(type_id)
|
|
}
|
|
|
|
/// Gets the component of the given [`ComponentId`] from the entity.
|
|
///
|
|
/// **You should prefer to use the typed API [`Self::get`] where possible and only
|
|
/// use this in cases where the actual component types are not known at
|
|
/// compile time.**
|
|
///
|
|
/// Unlike [`EntityMutExcept::get`], this returns a raw pointer to the component,
|
|
/// which is only valid while the [`EntityMutExcept`] is alive.
|
|
#[inline]
|
|
pub fn get_by_id(&'w self, component_id: ComponentId) -> Option<Ptr<'w>> {
|
|
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 [`Self::get_mut`] where possible and only
|
|
/// use this in cases where the actual component types are not known at
|
|
/// compile time.**
|
|
///
|
|
/// Unlike [`EntityMutExcept::get_mut`], this returns a raw pointer to the component,
|
|
/// which is only valid while the [`EntityMutExcept`] is alive.
|
|
#[inline]
|
|
pub fn get_mut_by_id<F: DynamicComponentFetch>(
|
|
&mut self,
|
|
component_id: ComponentId,
|
|
) -> Option<MutUntyped<'_>> {
|
|
let components = self.entity.world().components();
|
|
(!bundle_contains_component::<B>(components, component_id))
|
|
.then(|| {
|
|
// SAFETY: We have write access
|
|
unsafe { self.entity.get_mut_by_id(component_id).ok() }
|
|
})
|
|
.flatten()
|
|
}
|
|
}
|
|
|
|
impl<B: Bundle> PartialEq for EntityMutExcept<'_, B> {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.entity() == other.entity()
|
|
}
|
|
}
|
|
|
|
impl<B: Bundle> Eq for EntityMutExcept<'_, B> {}
|
|
|
|
impl<B: Bundle> PartialOrd for EntityMutExcept<'_, B> {
|
|
/// [`EntityMutExcept`]'s comparison trait implementations match the underlying [`Entity`],
|
|
/// and cannot discern between different worlds.
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
Some(self.cmp(other))
|
|
}
|
|
}
|
|
|
|
impl<B: Bundle> Ord for EntityMutExcept<'_, B> {
|
|
fn cmp(&self, other: &Self) -> Ordering {
|
|
self.entity().cmp(&other.entity())
|
|
}
|
|
}
|
|
|
|
impl<B: Bundle> Hash for EntityMutExcept<'_, B> {
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
self.entity().hash(state);
|
|
}
|
|
}
|
|
|
|
impl<B: Bundle> ContainsEntity for EntityMutExcept<'_, B> {
|
|
fn entity(&self) -> Entity {
|
|
self.id()
|
|
}
|
|
}
|
|
|
|
// SAFETY: This type represents one Entity. We implement the comparison traits based on that Entity.
|
|
unsafe impl<B: Bundle> EntityEquivalent for EntityMutExcept<'_, B> {}
|
|
|
|
fn bundle_contains_component<B>(components: &Components, query_id: ComponentId) -> bool
|
|
where
|
|
B: Bundle,
|
|
{
|
|
let mut found = false;
|
|
B::get_component_ids(components, &mut |maybe_id| {
|
|
if let Some(id) = maybe_id {
|
|
found = found || id == query_id;
|
|
}
|
|
});
|
|
found
|
|
}
|
|
|
|
/// Inserts a dynamic [`Bundle`] into the entity.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// - [`OwningPtr`] and [`StorageType`] iterators must correspond to the
|
|
/// [`BundleInfo`](crate::bundle::BundleInfo) used to construct [`BundleInserter`]
|
|
/// - [`Entity`] must correspond to [`EntityLocation`]
|
|
unsafe fn insert_dynamic_bundle<
|
|
'a,
|
|
I: Iterator<Item = OwningPtr<'a>>,
|
|
S: Iterator<Item = StorageType>,
|
|
>(
|
|
mut bundle_inserter: BundleInserter<'_>,
|
|
entity: Entity,
|
|
location: EntityLocation,
|
|
components: I,
|
|
storage_types: S,
|
|
mode: InsertMode,
|
|
caller: MaybeLocation,
|
|
relationship_hook_insert_mode: RelationshipHookMode,
|
|
) -> EntityLocation {
|
|
struct DynamicInsertBundle<'a, I: Iterator<Item = (StorageType, OwningPtr<'a>)>> {
|
|
components: I,
|
|
}
|
|
|
|
impl<'a, I: Iterator<Item = (StorageType, OwningPtr<'a>)>> DynamicBundle
|
|
for DynamicInsertBundle<'a, I>
|
|
{
|
|
type Effect = ();
|
|
fn get_components(self, func: &mut impl FnMut(StorageType, OwningPtr<'_>)) {
|
|
self.components.for_each(|(t, ptr)| func(t, ptr));
|
|
}
|
|
}
|
|
|
|
let bundle = DynamicInsertBundle {
|
|
components: storage_types.zip(components),
|
|
};
|
|
|
|
// SAFETY: location matches current entity.
|
|
unsafe {
|
|
bundle_inserter
|
|
.insert(
|
|
entity,
|
|
location,
|
|
bundle,
|
|
mode,
|
|
caller,
|
|
relationship_hook_insert_mode,
|
|
)
|
|
.0
|
|
}
|
|
}
|
|
|
|
/// Types that can be used to fetch components from an entity dynamically by
|
|
/// [`ComponentId`]s.
|
|
///
|
|
/// Provided implementations are:
|
|
/// - [`ComponentId`]: Returns a single untyped reference.
|
|
/// - `[ComponentId; N]` and `&[ComponentId; N]`: Returns a same-sized array of untyped references.
|
|
/// - `&[ComponentId]`: Returns a [`Vec`] of untyped references.
|
|
/// - [`&HashSet<ComponentId>`](HashSet): Returns a [`HashMap`] of IDs to untyped references.
|
|
///
|
|
/// # Performance
|
|
///
|
|
/// - The slice and array implementations perform an aliased mutability check in
|
|
/// [`DynamicComponentFetch::fetch_mut`] that is `O(N^2)`.
|
|
/// - The [`HashSet`] implementation performs no such check as the type itself
|
|
/// guarantees unique IDs.
|
|
/// - The single [`ComponentId`] implementation performs no such check as only
|
|
/// one reference is returned.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// Implementor must ensure that:
|
|
/// - No aliased mutability is caused by the returned references.
|
|
/// - [`DynamicComponentFetch::fetch_ref`] returns only read-only references.
|
|
pub unsafe trait DynamicComponentFetch {
|
|
/// The read-only reference type returned by [`DynamicComponentFetch::fetch_ref`].
|
|
type Ref<'w>;
|
|
|
|
/// The mutable reference type returned by [`DynamicComponentFetch::fetch_mut`].
|
|
type Mut<'w>;
|
|
|
|
/// Returns untyped read-only reference(s) to the component(s) with the
|
|
/// given [`ComponentId`]s, as determined by `self`.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// It is the caller's responsibility to ensure that:
|
|
/// - The given [`UnsafeEntityCell`] has read-only access to the fetched components.
|
|
/// - No other mutable references to the fetched components exist at the same time.
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// - Returns [`EntityComponentError::MissingComponent`] if a component is missing from the entity.
|
|
unsafe fn fetch_ref(
|
|
self,
|
|
cell: UnsafeEntityCell<'_>,
|
|
) -> Result<Self::Ref<'_>, EntityComponentError>;
|
|
|
|
/// Returns untyped mutable reference(s) to the component(s) with the
|
|
/// given [`ComponentId`]s, as determined by `self`.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// It is the caller's responsibility to ensure that:
|
|
/// - The given [`UnsafeEntityCell`] has mutable access to the fetched components.
|
|
/// - No other references to the fetched components exist at the same time.
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// - Returns [`EntityComponentError::MissingComponent`] if a component is missing from the entity.
|
|
/// - Returns [`EntityComponentError::AliasedMutability`] if a component is requested multiple times.
|
|
unsafe fn fetch_mut(
|
|
self,
|
|
cell: UnsafeEntityCell<'_>,
|
|
) -> Result<Self::Mut<'_>, EntityComponentError>;
|
|
|
|
/// Returns untyped mutable reference(s) to the component(s) with the
|
|
/// given [`ComponentId`]s, as determined by `self`.
|
|
/// Assumes all [`ComponentId`]s refer to mutable components.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// It is the caller's responsibility to ensure that:
|
|
/// - The given [`UnsafeEntityCell`] has mutable access to the fetched components.
|
|
/// - No other references to the fetched components exist at the same time.
|
|
/// - The requested components are all mutable.
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// - Returns [`EntityComponentError::MissingComponent`] if a component is missing from the entity.
|
|
/// - Returns [`EntityComponentError::AliasedMutability`] if a component is requested multiple times.
|
|
unsafe fn fetch_mut_assume_mutable(
|
|
self,
|
|
cell: UnsafeEntityCell<'_>,
|
|
) -> Result<Self::Mut<'_>, EntityComponentError>;
|
|
}
|
|
|
|
// SAFETY:
|
|
// - No aliased mutability is caused because a single reference is returned.
|
|
// - No mutable references are returned by `fetch_ref`.
|
|
unsafe impl DynamicComponentFetch for ComponentId {
|
|
type Ref<'w> = Ptr<'w>;
|
|
type Mut<'w> = MutUntyped<'w>;
|
|
|
|
unsafe fn fetch_ref(
|
|
self,
|
|
cell: UnsafeEntityCell<'_>,
|
|
) -> Result<Self::Ref<'_>, EntityComponentError> {
|
|
// SAFETY: caller ensures that the cell has read access to the component.
|
|
unsafe { cell.get_by_id(self) }.ok_or(EntityComponentError::MissingComponent(self))
|
|
}
|
|
|
|
unsafe fn fetch_mut(
|
|
self,
|
|
cell: UnsafeEntityCell<'_>,
|
|
) -> Result<Self::Mut<'_>, EntityComponentError> {
|
|
// SAFETY: caller ensures that the cell has mutable access to the component.
|
|
unsafe { cell.get_mut_by_id(self) }
|
|
.map_err(|_| EntityComponentError::MissingComponent(self))
|
|
}
|
|
|
|
unsafe fn fetch_mut_assume_mutable(
|
|
self,
|
|
cell: UnsafeEntityCell<'_>,
|
|
) -> Result<Self::Mut<'_>, EntityComponentError> {
|
|
// SAFETY: caller ensures that the cell has mutable access to the component.
|
|
unsafe { cell.get_mut_assume_mutable_by_id(self) }
|
|
.map_err(|_| EntityComponentError::MissingComponent(self))
|
|
}
|
|
}
|
|
|
|
// SAFETY:
|
|
// - No aliased mutability is caused because the array is checked for duplicates.
|
|
// - No mutable references are returned by `fetch_ref`.
|
|
unsafe impl<const N: usize> DynamicComponentFetch for [ComponentId; N] {
|
|
type Ref<'w> = [Ptr<'w>; N];
|
|
type Mut<'w> = [MutUntyped<'w>; N];
|
|
|
|
unsafe fn fetch_ref(
|
|
self,
|
|
cell: UnsafeEntityCell<'_>,
|
|
) -> Result<Self::Ref<'_>, EntityComponentError> {
|
|
<&Self>::fetch_ref(&self, cell)
|
|
}
|
|
|
|
unsafe fn fetch_mut(
|
|
self,
|
|
cell: UnsafeEntityCell<'_>,
|
|
) -> Result<Self::Mut<'_>, EntityComponentError> {
|
|
<&Self>::fetch_mut(&self, cell)
|
|
}
|
|
|
|
unsafe fn fetch_mut_assume_mutable(
|
|
self,
|
|
cell: UnsafeEntityCell<'_>,
|
|
) -> Result<Self::Mut<'_>, EntityComponentError> {
|
|
<&Self>::fetch_mut_assume_mutable(&self, cell)
|
|
}
|
|
}
|
|
|
|
// SAFETY:
|
|
// - No aliased mutability is caused because the array is checked for duplicates.
|
|
// - No mutable references are returned by `fetch_ref`.
|
|
unsafe impl<const N: usize> DynamicComponentFetch for &'_ [ComponentId; N] {
|
|
type Ref<'w> = [Ptr<'w>; N];
|
|
type Mut<'w> = [MutUntyped<'w>; N];
|
|
|
|
unsafe fn fetch_ref(
|
|
self,
|
|
cell: UnsafeEntityCell<'_>,
|
|
) -> Result<Self::Ref<'_>, EntityComponentError> {
|
|
let mut ptrs = [const { MaybeUninit::uninit() }; N];
|
|
for (ptr, &id) in core::iter::zip(&mut ptrs, self) {
|
|
*ptr = MaybeUninit::new(
|
|
// SAFETY: caller ensures that the cell has read access to the component.
|
|
unsafe { cell.get_by_id(id) }.ok_or(EntityComponentError::MissingComponent(id))?,
|
|
);
|
|
}
|
|
|
|
// SAFETY: Each ptr was initialized in the loop above.
|
|
let ptrs = ptrs.map(|ptr| unsafe { MaybeUninit::assume_init(ptr) });
|
|
|
|
Ok(ptrs)
|
|
}
|
|
|
|
unsafe fn fetch_mut(
|
|
self,
|
|
cell: UnsafeEntityCell<'_>,
|
|
) -> Result<Self::Mut<'_>, EntityComponentError> {
|
|
// Check for duplicate component IDs.
|
|
for i in 0..self.len() {
|
|
for j in 0..i {
|
|
if self[i] == self[j] {
|
|
return Err(EntityComponentError::AliasedMutability(self[i]));
|
|
}
|
|
}
|
|
}
|
|
|
|
let mut ptrs = [const { MaybeUninit::uninit() }; N];
|
|
for (ptr, &id) in core::iter::zip(&mut ptrs, self) {
|
|
*ptr = MaybeUninit::new(
|
|
// SAFETY: caller ensures that the cell has mutable access to the component.
|
|
unsafe { cell.get_mut_by_id(id) }
|
|
.map_err(|_| EntityComponentError::MissingComponent(id))?,
|
|
);
|
|
}
|
|
|
|
// SAFETY: Each ptr was initialized in the loop above.
|
|
let ptrs = ptrs.map(|ptr| unsafe { MaybeUninit::assume_init(ptr) });
|
|
|
|
Ok(ptrs)
|
|
}
|
|
|
|
unsafe fn fetch_mut_assume_mutable(
|
|
self,
|
|
cell: UnsafeEntityCell<'_>,
|
|
) -> Result<Self::Mut<'_>, EntityComponentError> {
|
|
// Check for duplicate component IDs.
|
|
for i in 0..self.len() {
|
|
for j in 0..i {
|
|
if self[i] == self[j] {
|
|
return Err(EntityComponentError::AliasedMutability(self[i]));
|
|
}
|
|
}
|
|
}
|
|
|
|
let mut ptrs = [const { MaybeUninit::uninit() }; N];
|
|
for (ptr, &id) in core::iter::zip(&mut ptrs, self) {
|
|
*ptr = MaybeUninit::new(
|
|
// SAFETY: caller ensures that the cell has mutable access to the component.
|
|
unsafe { cell.get_mut_assume_mutable_by_id(id) }
|
|
.map_err(|_| EntityComponentError::MissingComponent(id))?,
|
|
);
|
|
}
|
|
|
|
// SAFETY: Each ptr was initialized in the loop above.
|
|
let ptrs = ptrs.map(|ptr| unsafe { MaybeUninit::assume_init(ptr) });
|
|
|
|
Ok(ptrs)
|
|
}
|
|
}
|
|
|
|
// SAFETY:
|
|
// - No aliased mutability is caused because the slice is checked for duplicates.
|
|
// - No mutable references are returned by `fetch_ref`.
|
|
unsafe impl DynamicComponentFetch for &'_ [ComponentId] {
|
|
type Ref<'w> = Vec<Ptr<'w>>;
|
|
type Mut<'w> = Vec<MutUntyped<'w>>;
|
|
|
|
unsafe fn fetch_ref(
|
|
self,
|
|
cell: UnsafeEntityCell<'_>,
|
|
) -> Result<Self::Ref<'_>, EntityComponentError> {
|
|
let mut ptrs = Vec::with_capacity(self.len());
|
|
for &id in self {
|
|
ptrs.push(
|
|
// SAFETY: caller ensures that the cell has read access to the component.
|
|
unsafe { cell.get_by_id(id) }.ok_or(EntityComponentError::MissingComponent(id))?,
|
|
);
|
|
}
|
|
Ok(ptrs)
|
|
}
|
|
|
|
unsafe fn fetch_mut(
|
|
self,
|
|
cell: UnsafeEntityCell<'_>,
|
|
) -> Result<Self::Mut<'_>, EntityComponentError> {
|
|
// Check for duplicate component IDs.
|
|
for i in 0..self.len() {
|
|
for j in 0..i {
|
|
if self[i] == self[j] {
|
|
return Err(EntityComponentError::AliasedMutability(self[i]));
|
|
}
|
|
}
|
|
}
|
|
|
|
let mut ptrs = Vec::with_capacity(self.len());
|
|
for &id in self {
|
|
ptrs.push(
|
|
// SAFETY: caller ensures that the cell has mutable access to the component.
|
|
unsafe { cell.get_mut_by_id(id) }
|
|
.map_err(|_| EntityComponentError::MissingComponent(id))?,
|
|
);
|
|
}
|
|
Ok(ptrs)
|
|
}
|
|
|
|
unsafe fn fetch_mut_assume_mutable(
|
|
self,
|
|
cell: UnsafeEntityCell<'_>,
|
|
) -> Result<Self::Mut<'_>, EntityComponentError> {
|
|
// Check for duplicate component IDs.
|
|
for i in 0..self.len() {
|
|
for j in 0..i {
|
|
if self[i] == self[j] {
|
|
return Err(EntityComponentError::AliasedMutability(self[i]));
|
|
}
|
|
}
|
|
}
|
|
|
|
let mut ptrs = Vec::with_capacity(self.len());
|
|
for &id in self {
|
|
ptrs.push(
|
|
// SAFETY: caller ensures that the cell has mutable access to the component.
|
|
unsafe { cell.get_mut_assume_mutable_by_id(id) }
|
|
.map_err(|_| EntityComponentError::MissingComponent(id))?,
|
|
);
|
|
}
|
|
Ok(ptrs)
|
|
}
|
|
}
|
|
|
|
// SAFETY:
|
|
// - No aliased mutability is caused because `HashSet` guarantees unique elements.
|
|
// - No mutable references are returned by `fetch_ref`.
|
|
unsafe impl DynamicComponentFetch for &'_ HashSet<ComponentId> {
|
|
type Ref<'w> = HashMap<ComponentId, Ptr<'w>>;
|
|
type Mut<'w> = HashMap<ComponentId, MutUntyped<'w>>;
|
|
|
|
unsafe fn fetch_ref(
|
|
self,
|
|
cell: UnsafeEntityCell<'_>,
|
|
) -> Result<Self::Ref<'_>, EntityComponentError> {
|
|
let mut ptrs = HashMap::with_capacity_and_hasher(self.len(), Default::default());
|
|
for &id in self {
|
|
ptrs.insert(
|
|
id,
|
|
// SAFETY: caller ensures that the cell has read access to the component.
|
|
unsafe { cell.get_by_id(id) }.ok_or(EntityComponentError::MissingComponent(id))?,
|
|
);
|
|
}
|
|
Ok(ptrs)
|
|
}
|
|
|
|
unsafe fn fetch_mut(
|
|
self,
|
|
cell: UnsafeEntityCell<'_>,
|
|
) -> Result<Self::Mut<'_>, EntityComponentError> {
|
|
let mut ptrs = HashMap::with_capacity_and_hasher(self.len(), Default::default());
|
|
for &id in self {
|
|
ptrs.insert(
|
|
id,
|
|
// SAFETY: caller ensures that the cell has mutable access to the component.
|
|
unsafe { cell.get_mut_by_id(id) }
|
|
.map_err(|_| EntityComponentError::MissingComponent(id))?,
|
|
);
|
|
}
|
|
Ok(ptrs)
|
|
}
|
|
|
|
unsafe fn fetch_mut_assume_mutable(
|
|
self,
|
|
cell: UnsafeEntityCell<'_>,
|
|
) -> Result<Self::Mut<'_>, EntityComponentError> {
|
|
let mut ptrs = HashMap::with_capacity_and_hasher(self.len(), Default::default());
|
|
for &id in self {
|
|
ptrs.insert(
|
|
id,
|
|
// SAFETY: caller ensures that the cell has mutable access to the component.
|
|
unsafe { cell.get_mut_assume_mutable_by_id(id) }
|
|
.map_err(|_| EntityComponentError::MissingComponent(id))?,
|
|
);
|
|
}
|
|
Ok(ptrs)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use alloc::{vec, vec::Vec};
|
|
use bevy_ptr::{OwningPtr, Ptr};
|
|
use core::panic::AssertUnwindSafe;
|
|
use std::sync::OnceLock;
|
|
|
|
use crate::component::HookContext;
|
|
use crate::{
|
|
change_detection::{MaybeLocation, MutUntyped},
|
|
component::ComponentId,
|
|
prelude::*,
|
|
system::{assert_is_system, RunSystemOnce as _},
|
|
world::{error::EntityComponentError, DeferredWorld, FilteredEntityMut, FilteredEntityRef},
|
|
};
|
|
|
|
use super::{EntityMutExcept, EntityRefExcept};
|
|
|
|
#[derive(Component, Clone, Copy, Debug, PartialEq)]
|
|
struct TestComponent(u32);
|
|
|
|
#[derive(Component, Clone, Copy, Debug, PartialEq)]
|
|
#[component(storage = "SparseSet")]
|
|
struct TestComponent2(u32);
|
|
|
|
#[test]
|
|
fn entity_ref_get_by_id() {
|
|
let mut world = World::new();
|
|
let entity = world.spawn(TestComponent(42)).id();
|
|
let component_id = world
|
|
.components()
|
|
.get_id(core::any::TypeId::of::<TestComponent>())
|
|
.unwrap();
|
|
|
|
let entity = world.entity(entity);
|
|
let test_component = entity.get_by_id(component_id).unwrap();
|
|
// SAFETY: points to a valid `TestComponent`
|
|
let test_component = unsafe { test_component.deref::<TestComponent>() };
|
|
|
|
assert_eq!(test_component.0, 42);
|
|
}
|
|
|
|
#[test]
|
|
fn entity_mut_get_by_id() {
|
|
let mut world = World::new();
|
|
let entity = world.spawn(TestComponent(42)).id();
|
|
let component_id = world
|
|
.components()
|
|
.get_id(core::any::TypeId::of::<TestComponent>())
|
|
.unwrap();
|
|
|
|
let mut entity_mut = world.entity_mut(entity);
|
|
let mut test_component = entity_mut.get_mut_by_id(component_id).unwrap();
|
|
{
|
|
test_component.set_changed();
|
|
let test_component =
|
|
// SAFETY: `test_component` has unique access of the `EntityWorldMut` and is not used afterwards
|
|
unsafe { test_component.into_inner().deref_mut::<TestComponent>() };
|
|
test_component.0 = 43;
|
|
}
|
|
|
|
let entity = world.entity(entity);
|
|
let test_component = entity.get_by_id(component_id).unwrap();
|
|
// SAFETY: `TestComponent` is the correct component type
|
|
let test_component = unsafe { test_component.deref::<TestComponent>() };
|
|
|
|
assert_eq!(test_component.0, 43);
|
|
}
|
|
|
|
#[test]
|
|
fn entity_ref_get_by_id_invalid_component_id() {
|
|
let invalid_component_id = ComponentId::new(usize::MAX);
|
|
|
|
let mut world = World::new();
|
|
let entity = world.spawn_empty().id();
|
|
let entity = world.entity(entity);
|
|
assert!(entity.get_by_id(invalid_component_id).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn entity_mut_get_by_id_invalid_component_id() {
|
|
let invalid_component_id = ComponentId::new(usize::MAX);
|
|
|
|
let mut world = World::new();
|
|
let mut entity = world.spawn_empty();
|
|
assert!(entity.get_by_id(invalid_component_id).is_err());
|
|
assert!(entity.get_mut_by_id(invalid_component_id).is_err());
|
|
}
|
|
|
|
// regression test for https://github.com/bevyengine/bevy/pull/7387
|
|
#[test]
|
|
fn entity_mut_world_scope_panic() {
|
|
let mut world = World::new();
|
|
|
|
let mut entity = world.spawn_empty();
|
|
let old_location = entity.location();
|
|
let id = entity.id();
|
|
let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
|
|
entity.world_scope(|w| {
|
|
// Change the entity's `EntityLocation`, which invalidates the original `EntityWorldMut`.
|
|
// This will get updated at the end of the scope.
|
|
w.entity_mut(id).insert(TestComponent(0));
|
|
|
|
// Ensure that the entity location still gets updated even in case of a panic.
|
|
panic!("this should get caught by the outer scope")
|
|
});
|
|
}));
|
|
assert!(res.is_err());
|
|
|
|
// Ensure that the location has been properly updated.
|
|
assert_ne!(entity.location(), old_location);
|
|
}
|
|
|
|
// regression test for https://github.com/bevyengine/bevy/pull/7805
|
|
#[test]
|
|
fn removing_sparse_updates_archetype_row() {
|
|
#[derive(Component, PartialEq, Debug)]
|
|
struct Dense(u8);
|
|
|
|
#[derive(Component)]
|
|
#[component(storage = "SparseSet")]
|
|
struct Sparse;
|
|
|
|
let mut world = World::new();
|
|
let e1 = world.spawn((Dense(0), Sparse)).id();
|
|
let e2 = world.spawn((Dense(1), Sparse)).id();
|
|
|
|
world.entity_mut(e1).remove::<Sparse>();
|
|
assert_eq!(world.entity(e2).get::<Dense>().unwrap(), &Dense(1));
|
|
}
|
|
|
|
// regression test for https://github.com/bevyengine/bevy/pull/7805
|
|
#[test]
|
|
fn removing_dense_updates_table_row() {
|
|
#[derive(Component, PartialEq, Debug)]
|
|
struct Dense(u8);
|
|
|
|
#[derive(Component)]
|
|
#[component(storage = "SparseSet")]
|
|
struct Sparse;
|
|
|
|
let mut world = World::new();
|
|
let e1 = world.spawn((Dense(0), Sparse)).id();
|
|
let e2 = world.spawn((Dense(1), Sparse)).id();
|
|
|
|
world.entity_mut(e1).remove::<Dense>();
|
|
assert_eq!(world.entity(e2).get::<Dense>().unwrap(), &Dense(1));
|
|
}
|
|
|
|
// Test that calling retain with `()` removes all components.
|
|
#[test]
|
|
fn retain_nothing() {
|
|
#[derive(Component)]
|
|
struct Marker<const N: usize>;
|
|
|
|
let mut world = World::new();
|
|
let ent = world.spawn((Marker::<1>, Marker::<2>, Marker::<3>)).id();
|
|
|
|
world.entity_mut(ent).retain::<()>();
|
|
assert_eq!(world.entity(ent).archetype().components().next(), None);
|
|
}
|
|
|
|
// Test removing some components with `retain`, including components not on the entity.
|
|
#[test]
|
|
fn retain_some_components() {
|
|
#[derive(Component)]
|
|
struct Marker<const N: usize>;
|
|
|
|
let mut world = World::new();
|
|
let ent = world.spawn((Marker::<1>, Marker::<2>, Marker::<3>)).id();
|
|
|
|
world.entity_mut(ent).retain::<(Marker<2>, Marker<4>)>();
|
|
// Check that marker 2 was retained.
|
|
assert!(world.entity(ent).get::<Marker<2>>().is_some());
|
|
// Check that only marker 2 was retained.
|
|
assert_eq!(
|
|
world
|
|
.entity(ent)
|
|
.archetype()
|
|
.components()
|
|
.collect::<Vec<_>>()
|
|
.len(),
|
|
1
|
|
);
|
|
}
|
|
|
|
// regression test for https://github.com/bevyengine/bevy/pull/7805
|
|
#[test]
|
|
fn inserting_sparse_updates_archetype_row() {
|
|
#[derive(Component, PartialEq, Debug)]
|
|
struct Dense(u8);
|
|
|
|
#[derive(Component)]
|
|
#[component(storage = "SparseSet")]
|
|
struct Sparse;
|
|
|
|
let mut world = World::new();
|
|
let e1 = world.spawn(Dense(0)).id();
|
|
let e2 = world.spawn(Dense(1)).id();
|
|
|
|
world.entity_mut(e1).insert(Sparse);
|
|
assert_eq!(world.entity(e2).get::<Dense>().unwrap(), &Dense(1));
|
|
}
|
|
|
|
// regression test for https://github.com/bevyengine/bevy/pull/7805
|
|
#[test]
|
|
fn inserting_dense_updates_archetype_row() {
|
|
#[derive(Component, PartialEq, Debug)]
|
|
struct Dense(u8);
|
|
|
|
#[derive(Component)]
|
|
struct Dense2;
|
|
|
|
#[derive(Component)]
|
|
#[component(storage = "SparseSet")]
|
|
struct Sparse;
|
|
|
|
let mut world = World::new();
|
|
let e1 = world.spawn(Dense(0)).id();
|
|
let e2 = world.spawn(Dense(1)).id();
|
|
|
|
world.entity_mut(e1).insert(Sparse).remove::<Sparse>();
|
|
|
|
// archetype with [e2, e1]
|
|
// table with [e1, e2]
|
|
|
|
world.entity_mut(e2).insert(Dense2);
|
|
|
|
assert_eq!(world.entity(e1).get::<Dense>().unwrap(), &Dense(0));
|
|
}
|
|
|
|
#[test]
|
|
fn inserting_dense_updates_table_row() {
|
|
#[derive(Component, PartialEq, Debug)]
|
|
struct Dense(u8);
|
|
|
|
#[derive(Component)]
|
|
struct Dense2;
|
|
|
|
#[derive(Component)]
|
|
#[component(storage = "SparseSet")]
|
|
struct Sparse;
|
|
|
|
let mut world = World::new();
|
|
let e1 = world.spawn(Dense(0)).id();
|
|
let e2 = world.spawn(Dense(1)).id();
|
|
|
|
world.entity_mut(e1).insert(Sparse).remove::<Sparse>();
|
|
|
|
// archetype with [e2, e1]
|
|
// table with [e1, e2]
|
|
|
|
world.entity_mut(e1).insert(Dense2);
|
|
|
|
assert_eq!(world.entity(e2).get::<Dense>().unwrap(), &Dense(1));
|
|
}
|
|
|
|
// regression test for https://github.com/bevyengine/bevy/pull/7805
|
|
#[test]
|
|
fn despawning_entity_updates_archetype_row() {
|
|
#[derive(Component, PartialEq, Debug)]
|
|
struct Dense(u8);
|
|
|
|
#[derive(Component)]
|
|
#[component(storage = "SparseSet")]
|
|
struct Sparse;
|
|
|
|
let mut world = World::new();
|
|
let e1 = world.spawn(Dense(0)).id();
|
|
let e2 = world.spawn(Dense(1)).id();
|
|
|
|
world.entity_mut(e1).insert(Sparse).remove::<Sparse>();
|
|
|
|
// archetype with [e2, e1]
|
|
// table with [e1, e2]
|
|
|
|
world.entity_mut(e2).despawn();
|
|
|
|
assert_eq!(world.entity(e1).get::<Dense>().unwrap(), &Dense(0));
|
|
}
|
|
|
|
// regression test for https://github.com/bevyengine/bevy/pull/7805
|
|
#[test]
|
|
fn despawning_entity_updates_table_row() {
|
|
#[derive(Component, PartialEq, Debug)]
|
|
struct Dense(u8);
|
|
|
|
#[derive(Component)]
|
|
#[component(storage = "SparseSet")]
|
|
struct Sparse;
|
|
|
|
let mut world = World::new();
|
|
let e1 = world.spawn(Dense(0)).id();
|
|
let e2 = world.spawn(Dense(1)).id();
|
|
|
|
world.entity_mut(e1).insert(Sparse).remove::<Sparse>();
|
|
|
|
// archetype with [e2, e1]
|
|
// table with [e1, e2]
|
|
|
|
world.entity_mut(e1).despawn();
|
|
|
|
assert_eq!(world.entity(e2).get::<Dense>().unwrap(), &Dense(1));
|
|
}
|
|
|
|
#[test]
|
|
fn entity_mut_insert_by_id() {
|
|
let mut world = World::new();
|
|
let test_component_id = world.register_component::<TestComponent>();
|
|
|
|
let mut entity = world.spawn_empty();
|
|
OwningPtr::make(TestComponent(42), |ptr| {
|
|
// SAFETY: `ptr` matches the component id
|
|
unsafe { entity.insert_by_id(test_component_id, ptr) };
|
|
});
|
|
|
|
let components: Vec<_> = world.query::<&TestComponent>().iter(&world).collect();
|
|
|
|
assert_eq!(components, vec![&TestComponent(42)]);
|
|
|
|
// Compare with `insert_bundle_by_id`
|
|
|
|
let mut entity = world.spawn_empty();
|
|
OwningPtr::make(TestComponent(84), |ptr| {
|
|
// SAFETY: `ptr` matches the component id
|
|
unsafe { entity.insert_by_ids(&[test_component_id], vec![ptr].into_iter()) };
|
|
});
|
|
|
|
let components: Vec<_> = world.query::<&TestComponent>().iter(&world).collect();
|
|
|
|
assert_eq!(components, vec![&TestComponent(42), &TestComponent(84)]);
|
|
}
|
|
|
|
#[test]
|
|
fn entity_mut_insert_bundle_by_id() {
|
|
let mut world = World::new();
|
|
let test_component_id = world.register_component::<TestComponent>();
|
|
let test_component_2_id = world.register_component::<TestComponent2>();
|
|
|
|
let component_ids = [test_component_id, test_component_2_id];
|
|
let test_component_value = TestComponent(42);
|
|
let test_component_2_value = TestComponent2(84);
|
|
|
|
let mut entity = world.spawn_empty();
|
|
OwningPtr::make(test_component_value, |ptr1| {
|
|
OwningPtr::make(test_component_2_value, |ptr2| {
|
|
// SAFETY: `ptr1` and `ptr2` match the component ids
|
|
unsafe { entity.insert_by_ids(&component_ids, vec![ptr1, ptr2].into_iter()) };
|
|
});
|
|
});
|
|
|
|
let dynamic_components: Vec<_> = world
|
|
.query::<(&TestComponent, &TestComponent2)>()
|
|
.iter(&world)
|
|
.collect();
|
|
|
|
assert_eq!(
|
|
dynamic_components,
|
|
vec![(&TestComponent(42), &TestComponent2(84))]
|
|
);
|
|
|
|
// Compare with `World` generated using static type equivalents
|
|
let mut static_world = World::new();
|
|
|
|
static_world.spawn((test_component_value, test_component_2_value));
|
|
let static_components: Vec<_> = static_world
|
|
.query::<(&TestComponent, &TestComponent2)>()
|
|
.iter(&static_world)
|
|
.collect();
|
|
|
|
assert_eq!(dynamic_components, static_components);
|
|
}
|
|
|
|
#[test]
|
|
fn entity_mut_remove_by_id() {
|
|
let mut world = World::new();
|
|
let test_component_id = world.register_component::<TestComponent>();
|
|
|
|
let mut entity = world.spawn(TestComponent(42));
|
|
entity.remove_by_id(test_component_id);
|
|
|
|
let components: Vec<_> = world.query::<&TestComponent>().iter(&world).collect();
|
|
|
|
assert_eq!(components, vec![] as Vec<&TestComponent>);
|
|
|
|
// remove non-existent component does not panic
|
|
world.spawn_empty().remove_by_id(test_component_id);
|
|
}
|
|
|
|
/// Tests that components can be accessed through an `EntityRefExcept`.
|
|
#[test]
|
|
fn entity_ref_except() {
|
|
let mut world = World::new();
|
|
world.register_component::<TestComponent>();
|
|
world.register_component::<TestComponent2>();
|
|
|
|
world.spawn(TestComponent(0)).insert(TestComponent2(0));
|
|
|
|
let mut query = world.query::<EntityRefExcept<TestComponent>>();
|
|
|
|
let mut found = false;
|
|
for entity_ref in query.iter_mut(&mut world) {
|
|
found = true;
|
|
assert!(entity_ref.get::<TestComponent>().is_none());
|
|
assert!(entity_ref.get_ref::<TestComponent>().is_none());
|
|
assert!(matches!(
|
|
entity_ref.get::<TestComponent2>(),
|
|
Some(TestComponent2(0))
|
|
));
|
|
}
|
|
|
|
assert!(found);
|
|
}
|
|
|
|
// Test that a single query can't both contain a mutable reference to a
|
|
// component C and an `EntityRefExcept` that doesn't include C among its
|
|
// exclusions.
|
|
#[test]
|
|
#[should_panic]
|
|
fn entity_ref_except_conflicts_with_self() {
|
|
let mut world = World::new();
|
|
world.spawn(TestComponent(0)).insert(TestComponent2(0));
|
|
|
|
// This should panic, because we have a mutable borrow on
|
|
// `TestComponent` but have a simultaneous indirect immutable borrow on
|
|
// that component via `EntityRefExcept`.
|
|
world.run_system_once(system).unwrap();
|
|
|
|
fn system(_: Query<(&mut TestComponent, EntityRefExcept<TestComponent2>)>) {}
|
|
}
|
|
|
|
// Test that an `EntityRefExcept` that doesn't include a component C among
|
|
// its exclusions can't coexist with a mutable query for that component.
|
|
#[test]
|
|
#[should_panic]
|
|
fn entity_ref_except_conflicts_with_other() {
|
|
let mut world = World::new();
|
|
world.spawn(TestComponent(0)).insert(TestComponent2(0));
|
|
|
|
// This should panic, because we have a mutable borrow on
|
|
// `TestComponent` but have a simultaneous indirect immutable borrow on
|
|
// that component via `EntityRefExcept`.
|
|
world.run_system_once(system).unwrap();
|
|
|
|
fn system(_: Query<&mut TestComponent>, _: Query<EntityRefExcept<TestComponent2>>) {}
|
|
}
|
|
|
|
// Test that an `EntityRefExcept` with an exception for some component C can
|
|
// coexist with a query for that component C.
|
|
#[test]
|
|
fn entity_ref_except_doesnt_conflict() {
|
|
let mut world = World::new();
|
|
world.spawn(TestComponent(0)).insert(TestComponent2(0));
|
|
|
|
world.run_system_once(system).unwrap();
|
|
|
|
fn system(_: Query<&mut TestComponent>, query: Query<EntityRefExcept<TestComponent>>) {
|
|
for entity_ref in query.iter() {
|
|
assert!(matches!(
|
|
entity_ref.get::<TestComponent2>(),
|
|
Some(TestComponent2(0))
|
|
));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Tests that components can be mutably accessed through an
|
|
/// `EntityMutExcept`.
|
|
#[test]
|
|
fn entity_mut_except() {
|
|
let mut world = World::new();
|
|
world.spawn(TestComponent(0)).insert(TestComponent2(0));
|
|
|
|
let mut query = world.query::<EntityMutExcept<TestComponent>>();
|
|
|
|
let mut found = false;
|
|
for mut entity_mut in query.iter_mut(&mut world) {
|
|
found = true;
|
|
assert!(entity_mut.get::<TestComponent>().is_none());
|
|
assert!(entity_mut.get_ref::<TestComponent>().is_none());
|
|
assert!(entity_mut.get_mut::<TestComponent>().is_none());
|
|
assert!(matches!(
|
|
entity_mut.get::<TestComponent2>(),
|
|
Some(TestComponent2(0))
|
|
));
|
|
}
|
|
|
|
assert!(found);
|
|
}
|
|
|
|
// Test that a single query can't both contain a mutable reference to a
|
|
// component C and an `EntityMutExcept` that doesn't include C among its
|
|
// exclusions.
|
|
#[test]
|
|
#[should_panic]
|
|
fn entity_mut_except_conflicts_with_self() {
|
|
let mut world = World::new();
|
|
world.spawn(TestComponent(0)).insert(TestComponent2(0));
|
|
|
|
// This should panic, because we have a mutable borrow on
|
|
// `TestComponent` but have a simultaneous indirect immutable borrow on
|
|
// that component via `EntityRefExcept`.
|
|
world.run_system_once(system).unwrap();
|
|
|
|
fn system(_: Query<(&mut TestComponent, EntityMutExcept<TestComponent2>)>) {}
|
|
}
|
|
|
|
// Test that an `EntityMutExcept` that doesn't include a component C among
|
|
// its exclusions can't coexist with a query for that component.
|
|
#[test]
|
|
#[should_panic]
|
|
fn entity_mut_except_conflicts_with_other() {
|
|
let mut world = World::new();
|
|
world.spawn(TestComponent(0)).insert(TestComponent2(0));
|
|
|
|
// This should panic, because we have a mutable borrow on
|
|
// `TestComponent` but have a simultaneous indirect immutable borrow on
|
|
// that component via `EntityRefExcept`.
|
|
world.run_system_once(system).unwrap();
|
|
|
|
fn system(_: Query<&mut TestComponent>, mut query: Query<EntityMutExcept<TestComponent2>>) {
|
|
for mut entity_mut in query.iter_mut() {
|
|
assert!(entity_mut
|
|
.get_mut::<TestComponent2>()
|
|
.is_some_and(|component| component.0 == 0));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test that an `EntityMutExcept` with an exception for some component C can
|
|
// coexist with a query for that component C.
|
|
#[test]
|
|
fn entity_mut_except_doesnt_conflict() {
|
|
let mut world = World::new();
|
|
world.spawn(TestComponent(0)).insert(TestComponent2(0));
|
|
|
|
world.run_system_once(system).unwrap();
|
|
|
|
fn system(_: Query<&mut TestComponent>, mut query: Query<EntityMutExcept<TestComponent>>) {
|
|
for mut entity_mut in query.iter_mut() {
|
|
assert!(entity_mut
|
|
.get_mut::<TestComponent2>()
|
|
.is_some_and(|component| component.0 == 0));
|
|
}
|
|
}
|
|
}
|
|
|
|
#[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]
|
|
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]
|
|
fn mut_compatible_with_resource() {
|
|
fn borrow_mut_system(_: Res<R>, _: Query<EntityMut>) {}
|
|
|
|
assert_is_system(borrow_mut_system);
|
|
}
|
|
|
|
#[test]
|
|
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);
|
|
}
|
|
|
|
#[test]
|
|
fn filtered_entity_ref_normal() {
|
|
let mut world = World::new();
|
|
let a_id = world.register_component::<A>();
|
|
|
|
let e: FilteredEntityRef = world.spawn(A).into();
|
|
|
|
assert!(e.get::<A>().is_some());
|
|
assert!(e.get_ref::<A>().is_some());
|
|
assert!(e.get_change_ticks::<A>().is_some());
|
|
assert!(e.get_by_id(a_id).is_some());
|
|
assert!(e.get_change_ticks_by_id(a_id).is_some());
|
|
}
|
|
|
|
#[test]
|
|
fn filtered_entity_ref_missing() {
|
|
let mut world = World::new();
|
|
let a_id = world.register_component::<A>();
|
|
|
|
let e: FilteredEntityRef = world.spawn(()).into();
|
|
|
|
assert!(e.get::<A>().is_none());
|
|
assert!(e.get_ref::<A>().is_none());
|
|
assert!(e.get_change_ticks::<A>().is_none());
|
|
assert!(e.get_by_id(a_id).is_none());
|
|
assert!(e.get_change_ticks_by_id(a_id).is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn filtered_entity_mut_normal() {
|
|
let mut world = World::new();
|
|
let a_id = world.register_component::<A>();
|
|
|
|
let mut e: FilteredEntityMut = world.spawn(A).into();
|
|
|
|
assert!(e.get::<A>().is_some());
|
|
assert!(e.get_ref::<A>().is_some());
|
|
assert!(e.get_mut::<A>().is_some());
|
|
assert!(e.get_change_ticks::<A>().is_some());
|
|
assert!(e.get_by_id(a_id).is_some());
|
|
assert!(e.get_mut_by_id(a_id).is_some());
|
|
assert!(e.get_change_ticks_by_id(a_id).is_some());
|
|
}
|
|
|
|
#[test]
|
|
fn filtered_entity_mut_missing() {
|
|
let mut world = World::new();
|
|
let a_id = world.register_component::<A>();
|
|
|
|
let mut e: FilteredEntityMut = world.spawn(()).into();
|
|
|
|
assert!(e.get::<A>().is_none());
|
|
assert!(e.get_ref::<A>().is_none());
|
|
assert!(e.get_mut::<A>().is_none());
|
|
assert!(e.get_change_ticks::<A>().is_none());
|
|
assert!(e.get_by_id(a_id).is_none());
|
|
assert!(e.get_mut_by_id(a_id).is_none());
|
|
assert!(e.get_change_ticks_by_id(a_id).is_none());
|
|
}
|
|
|
|
#[derive(Component, PartialEq, Eq, Debug)]
|
|
struct X(usize);
|
|
|
|
#[derive(Component, PartialEq, Eq, Debug)]
|
|
struct Y(usize);
|
|
|
|
#[test]
|
|
fn get_components() {
|
|
let mut world = World::default();
|
|
let e1 = world.spawn((X(7), Y(10))).id();
|
|
let e2 = world.spawn(X(8)).id();
|
|
let e3 = world.spawn_empty().id();
|
|
|
|
assert_eq!(
|
|
Some((&X(7), &Y(10))),
|
|
world.entity(e1).get_components::<(&X, &Y)>()
|
|
);
|
|
assert_eq!(None, world.entity(e2).get_components::<(&X, &Y)>());
|
|
assert_eq!(None, world.entity(e3).get_components::<(&X, &Y)>());
|
|
}
|
|
|
|
#[test]
|
|
fn get_by_id_array() {
|
|
let mut world = World::default();
|
|
let e1 = world.spawn((X(7), Y(10))).id();
|
|
let e2 = world.spawn(X(8)).id();
|
|
let e3 = world.spawn_empty().id();
|
|
|
|
let x_id = world.register_component::<X>();
|
|
let y_id = world.register_component::<Y>();
|
|
|
|
assert_eq!(
|
|
Ok((&X(7), &Y(10))),
|
|
world
|
|
.entity(e1)
|
|
.get_by_id([x_id, y_id])
|
|
.map(|[x_ptr, y_ptr]| {
|
|
// SAFETY: components match the id they were fetched with
|
|
(unsafe { x_ptr.deref::<X>() }, unsafe { y_ptr.deref::<Y>() })
|
|
})
|
|
);
|
|
assert_eq!(
|
|
Err(EntityComponentError::MissingComponent(y_id)),
|
|
world
|
|
.entity(e2)
|
|
.get_by_id([x_id, y_id])
|
|
.map(|[x_ptr, y_ptr]| {
|
|
// SAFETY: components match the id they were fetched with
|
|
(unsafe { x_ptr.deref::<X>() }, unsafe { y_ptr.deref::<Y>() })
|
|
})
|
|
);
|
|
assert_eq!(
|
|
Err(EntityComponentError::MissingComponent(x_id)),
|
|
world
|
|
.entity(e3)
|
|
.get_by_id([x_id, y_id])
|
|
.map(|[x_ptr, y_ptr]| {
|
|
// SAFETY: components match the id they were fetched with
|
|
(unsafe { x_ptr.deref::<X>() }, unsafe { y_ptr.deref::<Y>() })
|
|
})
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn get_by_id_vec() {
|
|
let mut world = World::default();
|
|
let e1 = world.spawn((X(7), Y(10))).id();
|
|
let e2 = world.spawn(X(8)).id();
|
|
let e3 = world.spawn_empty().id();
|
|
|
|
let x_id = world.register_component::<X>();
|
|
let y_id = world.register_component::<Y>();
|
|
|
|
assert_eq!(
|
|
Ok((&X(7), &Y(10))),
|
|
world
|
|
.entity(e1)
|
|
.get_by_id(&[x_id, y_id] as &[ComponentId])
|
|
.map(|ptrs| {
|
|
let Ok([x_ptr, y_ptr]): Result<[Ptr; 2], _> = ptrs.try_into() else {
|
|
panic!("get_by_id(slice) didn't return 2 elements")
|
|
};
|
|
|
|
// SAFETY: components match the id they were fetched with
|
|
(unsafe { x_ptr.deref::<X>() }, unsafe { y_ptr.deref::<Y>() })
|
|
})
|
|
);
|
|
assert_eq!(
|
|
Err(EntityComponentError::MissingComponent(y_id)),
|
|
world
|
|
.entity(e2)
|
|
.get_by_id(&[x_id, y_id] as &[ComponentId])
|
|
.map(|ptrs| {
|
|
let Ok([x_ptr, y_ptr]): Result<[Ptr; 2], _> = ptrs.try_into() else {
|
|
panic!("get_by_id(slice) didn't return 2 elements")
|
|
};
|
|
|
|
// SAFETY: components match the id they were fetched with
|
|
(unsafe { x_ptr.deref::<X>() }, unsafe { y_ptr.deref::<Y>() })
|
|
})
|
|
);
|
|
assert_eq!(
|
|
Err(EntityComponentError::MissingComponent(x_id)),
|
|
world
|
|
.entity(e3)
|
|
.get_by_id(&[x_id, y_id] as &[ComponentId])
|
|
.map(|ptrs| {
|
|
let Ok([x_ptr, y_ptr]): Result<[Ptr; 2], _> = ptrs.try_into() else {
|
|
panic!("get_by_id(slice) didn't return 2 elements")
|
|
};
|
|
|
|
// SAFETY: components match the id they were fetched with
|
|
(unsafe { x_ptr.deref::<X>() }, unsafe { y_ptr.deref::<Y>() })
|
|
})
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn get_mut_by_id_array() {
|
|
let mut world = World::default();
|
|
let e1 = world.spawn((X(7), Y(10))).id();
|
|
let e2 = world.spawn(X(8)).id();
|
|
let e3 = world.spawn_empty().id();
|
|
|
|
let x_id = world.register_component::<X>();
|
|
let y_id = world.register_component::<Y>();
|
|
|
|
assert_eq!(
|
|
Ok((&mut X(7), &mut Y(10))),
|
|
world
|
|
.entity_mut(e1)
|
|
.get_mut_by_id([x_id, y_id])
|
|
.map(|[x_ptr, y_ptr]| {
|
|
// SAFETY: components match the id they were fetched with
|
|
(unsafe { x_ptr.into_inner().deref_mut::<X>() }, unsafe {
|
|
y_ptr.into_inner().deref_mut::<Y>()
|
|
})
|
|
})
|
|
);
|
|
assert_eq!(
|
|
Err(EntityComponentError::MissingComponent(y_id)),
|
|
world
|
|
.entity_mut(e2)
|
|
.get_mut_by_id([x_id, y_id])
|
|
.map(|[x_ptr, y_ptr]| {
|
|
// SAFETY: components match the id they were fetched with
|
|
(unsafe { x_ptr.into_inner().deref_mut::<X>() }, unsafe {
|
|
y_ptr.into_inner().deref_mut::<Y>()
|
|
})
|
|
})
|
|
);
|
|
assert_eq!(
|
|
Err(EntityComponentError::MissingComponent(x_id)),
|
|
world
|
|
.entity_mut(e3)
|
|
.get_mut_by_id([x_id, y_id])
|
|
.map(|[x_ptr, y_ptr]| {
|
|
// SAFETY: components match the id they were fetched with
|
|
(unsafe { x_ptr.into_inner().deref_mut::<X>() }, unsafe {
|
|
y_ptr.into_inner().deref_mut::<Y>()
|
|
})
|
|
})
|
|
);
|
|
|
|
assert_eq!(
|
|
Err(EntityComponentError::AliasedMutability(x_id)),
|
|
world
|
|
.entity_mut(e1)
|
|
.get_mut_by_id([x_id, x_id])
|
|
.map(|_| { unreachable!() })
|
|
);
|
|
assert_eq!(
|
|
Err(EntityComponentError::AliasedMutability(x_id)),
|
|
world
|
|
.entity_mut(e3)
|
|
.get_mut_by_id([x_id, x_id])
|
|
.map(|_| { unreachable!() })
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn get_mut_by_id_vec() {
|
|
let mut world = World::default();
|
|
let e1 = world.spawn((X(7), Y(10))).id();
|
|
let e2 = world.spawn(X(8)).id();
|
|
let e3 = world.spawn_empty().id();
|
|
|
|
let x_id = world.register_component::<X>();
|
|
let y_id = world.register_component::<Y>();
|
|
|
|
assert_eq!(
|
|
Ok((&mut X(7), &mut Y(10))),
|
|
world
|
|
.entity_mut(e1)
|
|
.get_mut_by_id(&[x_id, y_id] as &[ComponentId])
|
|
.map(|ptrs| {
|
|
let Ok([x_ptr, y_ptr]): Result<[MutUntyped; 2], _> = ptrs.try_into() else {
|
|
panic!("get_mut_by_id(slice) didn't return 2 elements")
|
|
};
|
|
|
|
// SAFETY: components match the id they were fetched with
|
|
(unsafe { x_ptr.into_inner().deref_mut::<X>() }, unsafe {
|
|
y_ptr.into_inner().deref_mut::<Y>()
|
|
})
|
|
})
|
|
);
|
|
assert_eq!(
|
|
Err(EntityComponentError::MissingComponent(y_id)),
|
|
world
|
|
.entity_mut(e2)
|
|
.get_mut_by_id(&[x_id, y_id] as &[ComponentId])
|
|
.map(|ptrs| {
|
|
let Ok([x_ptr, y_ptr]): Result<[MutUntyped; 2], _> = ptrs.try_into() else {
|
|
panic!("get_mut_by_id(slice) didn't return 2 elements")
|
|
};
|
|
|
|
// SAFETY: components match the id they were fetched with
|
|
(unsafe { x_ptr.into_inner().deref_mut::<X>() }, unsafe {
|
|
y_ptr.into_inner().deref_mut::<Y>()
|
|
})
|
|
})
|
|
);
|
|
assert_eq!(
|
|
Err(EntityComponentError::MissingComponent(x_id)),
|
|
world
|
|
.entity_mut(e3)
|
|
.get_mut_by_id(&[x_id, y_id] as &[ComponentId])
|
|
.map(|ptrs| {
|
|
let Ok([x_ptr, y_ptr]): Result<[MutUntyped; 2], _> = ptrs.try_into() else {
|
|
panic!("get_mut_by_id(slice) didn't return 2 elements")
|
|
};
|
|
|
|
// SAFETY: components match the id they were fetched with
|
|
(unsafe { x_ptr.into_inner().deref_mut::<X>() }, unsafe {
|
|
y_ptr.into_inner().deref_mut::<Y>()
|
|
})
|
|
})
|
|
);
|
|
|
|
assert_eq!(
|
|
Err(EntityComponentError::AliasedMutability(x_id)),
|
|
world
|
|
.entity_mut(e1)
|
|
.get_mut_by_id(&[x_id, x_id])
|
|
.map(|_| { unreachable!() })
|
|
);
|
|
assert_eq!(
|
|
Err(EntityComponentError::AliasedMutability(x_id)),
|
|
world
|
|
.entity_mut(e3)
|
|
.get_mut_by_id(&[x_id, x_id])
|
|
.map(|_| { unreachable!() })
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn get_mut_by_id_unchecked() {
|
|
let mut world = World::default();
|
|
let e1 = world.spawn((X(7), Y(10))).id();
|
|
let x_id = world.register_component::<X>();
|
|
let y_id = world.register_component::<Y>();
|
|
|
|
let e1_mut = &world.get_entity_mut([e1]).unwrap()[0];
|
|
// SAFETY: The entity e1 contains component X.
|
|
let x_ptr = unsafe { e1_mut.get_mut_by_id_unchecked(x_id) }.unwrap();
|
|
// SAFETY: The entity e1 contains component Y, with components X and Y being mutually independent.
|
|
let y_ptr = unsafe { e1_mut.get_mut_by_id_unchecked(y_id) }.unwrap();
|
|
|
|
// SAFETY: components match the id they were fetched with
|
|
let x_component = unsafe { x_ptr.into_inner().deref_mut::<X>() };
|
|
x_component.0 += 1;
|
|
// SAFETY: components match the id they were fetched with
|
|
let y_component = unsafe { y_ptr.into_inner().deref_mut::<Y>() };
|
|
y_component.0 -= 1;
|
|
|
|
assert_eq!((&mut X(8), &mut Y(9)), (x_component, y_component));
|
|
}
|
|
|
|
#[derive(Event)]
|
|
struct TestEvent;
|
|
|
|
#[test]
|
|
fn adding_observer_updates_location() {
|
|
let mut world = World::new();
|
|
let entity = world
|
|
.spawn_empty()
|
|
.observe(|trigger: Trigger<TestEvent>, mut commands: Commands| {
|
|
commands.entity(trigger.target()).insert(TestComponent(0));
|
|
})
|
|
.id();
|
|
|
|
// this should not be needed, but is currently required to tease out the bug
|
|
world.flush();
|
|
|
|
let mut a = world.entity_mut(entity);
|
|
a.trigger(TestEvent); // this adds command to change entity archetype
|
|
a.observe(|_: Trigger<TestEvent>| {}); // this flushes commands implicitly by spawning
|
|
let location = a.location();
|
|
assert_eq!(world.entities().get(entity), Some(location));
|
|
}
|
|
|
|
#[test]
|
|
#[should_panic]
|
|
fn location_on_despawned_entity_panics() {
|
|
let mut world = World::new();
|
|
world.add_observer(
|
|
|trigger: Trigger<OnAdd, TestComponent>, mut commands: Commands| {
|
|
commands.entity(trigger.target()).despawn();
|
|
},
|
|
);
|
|
let entity = world.spawn_empty().id();
|
|
let mut a = world.entity_mut(entity);
|
|
a.insert(TestComponent(0));
|
|
a.location();
|
|
}
|
|
|
|
#[derive(Resource)]
|
|
struct TestFlush(usize);
|
|
|
|
fn count_flush(world: &mut World) {
|
|
world.resource_mut::<TestFlush>().0 += 1;
|
|
}
|
|
|
|
#[test]
|
|
fn archetype_modifications_trigger_flush() {
|
|
let mut world = World::new();
|
|
world.insert_resource(TestFlush(0));
|
|
world.add_observer(|_: Trigger<OnAdd, TestComponent>, mut commands: Commands| {
|
|
commands.queue(count_flush);
|
|
});
|
|
world.add_observer(
|
|
|_: Trigger<OnRemove, TestComponent>, mut commands: Commands| {
|
|
commands.queue(count_flush);
|
|
},
|
|
);
|
|
world.commands().queue(count_flush);
|
|
let entity = world.spawn_empty().id();
|
|
assert_eq!(world.resource::<TestFlush>().0, 1);
|
|
world.commands().queue(count_flush);
|
|
let mut a = world.entity_mut(entity);
|
|
a.trigger(TestEvent);
|
|
assert_eq!(a.world().resource::<TestFlush>().0, 2);
|
|
a.insert(TestComponent(0));
|
|
assert_eq!(a.world().resource::<TestFlush>().0, 3);
|
|
a.remove::<TestComponent>();
|
|
assert_eq!(a.world().resource::<TestFlush>().0, 4);
|
|
a.insert(TestComponent(0));
|
|
assert_eq!(a.world().resource::<TestFlush>().0, 5);
|
|
let _ = a.take::<TestComponent>();
|
|
assert_eq!(a.world().resource::<TestFlush>().0, 6);
|
|
a.insert(TestComponent(0));
|
|
assert_eq!(a.world().resource::<TestFlush>().0, 7);
|
|
a.retain::<()>();
|
|
assert_eq!(a.world().resource::<TestFlush>().0, 8);
|
|
a.insert(TestComponent(0));
|
|
assert_eq!(a.world().resource::<TestFlush>().0, 9);
|
|
a.clear();
|
|
assert_eq!(a.world().resource::<TestFlush>().0, 10);
|
|
a.insert(TestComponent(0));
|
|
assert_eq!(a.world().resource::<TestFlush>().0, 11);
|
|
a.despawn();
|
|
assert_eq!(world.resource::<TestFlush>().0, 12);
|
|
}
|
|
|
|
#[derive(Resource)]
|
|
struct TestVec(Vec<&'static str>);
|
|
|
|
#[derive(Component)]
|
|
#[component(on_add = ord_a_hook_on_add, on_insert = ord_a_hook_on_insert, on_replace = ord_a_hook_on_replace, on_remove = ord_a_hook_on_remove)]
|
|
struct OrdA;
|
|
|
|
fn ord_a_hook_on_add(mut world: DeferredWorld, HookContext { entity, .. }: HookContext) {
|
|
world.resource_mut::<TestVec>().0.push("OrdA hook on_add");
|
|
world.commands().entity(entity).insert(OrdB);
|
|
}
|
|
|
|
fn ord_a_hook_on_insert(mut world: DeferredWorld, HookContext { entity, .. }: HookContext) {
|
|
world
|
|
.resource_mut::<TestVec>()
|
|
.0
|
|
.push("OrdA hook on_insert");
|
|
world.commands().entity(entity).remove::<OrdA>();
|
|
world.commands().entity(entity).remove::<OrdB>();
|
|
}
|
|
|
|
fn ord_a_hook_on_replace(mut world: DeferredWorld, _: HookContext) {
|
|
world
|
|
.resource_mut::<TestVec>()
|
|
.0
|
|
.push("OrdA hook on_replace");
|
|
}
|
|
|
|
fn ord_a_hook_on_remove(mut world: DeferredWorld, _: HookContext) {
|
|
world
|
|
.resource_mut::<TestVec>()
|
|
.0
|
|
.push("OrdA hook on_remove");
|
|
}
|
|
|
|
fn ord_a_observer_on_add(_trigger: Trigger<OnAdd, OrdA>, mut res: ResMut<TestVec>) {
|
|
res.0.push("OrdA observer on_add");
|
|
}
|
|
|
|
fn ord_a_observer_on_insert(_trigger: Trigger<OnInsert, OrdA>, mut res: ResMut<TestVec>) {
|
|
res.0.push("OrdA observer on_insert");
|
|
}
|
|
|
|
fn ord_a_observer_on_replace(_trigger: Trigger<OnReplace, OrdA>, mut res: ResMut<TestVec>) {
|
|
res.0.push("OrdA observer on_replace");
|
|
}
|
|
|
|
fn ord_a_observer_on_remove(_trigger: Trigger<OnRemove, OrdA>, mut res: ResMut<TestVec>) {
|
|
res.0.push("OrdA observer on_remove");
|
|
}
|
|
|
|
#[derive(Component)]
|
|
#[component(on_add = ord_b_hook_on_add, on_insert = ord_b_hook_on_insert, on_replace = ord_b_hook_on_replace, on_remove = ord_b_hook_on_remove)]
|
|
struct OrdB;
|
|
|
|
fn ord_b_hook_on_add(mut world: DeferredWorld, _: HookContext) {
|
|
world.resource_mut::<TestVec>().0.push("OrdB hook on_add");
|
|
world.commands().queue(|world: &mut World| {
|
|
world
|
|
.resource_mut::<TestVec>()
|
|
.0
|
|
.push("OrdB command on_add");
|
|
});
|
|
}
|
|
|
|
fn ord_b_hook_on_insert(mut world: DeferredWorld, _: HookContext) {
|
|
world
|
|
.resource_mut::<TestVec>()
|
|
.0
|
|
.push("OrdB hook on_insert");
|
|
}
|
|
|
|
fn ord_b_hook_on_replace(mut world: DeferredWorld, _: HookContext) {
|
|
world
|
|
.resource_mut::<TestVec>()
|
|
.0
|
|
.push("OrdB hook on_replace");
|
|
}
|
|
|
|
fn ord_b_hook_on_remove(mut world: DeferredWorld, _: HookContext) {
|
|
world
|
|
.resource_mut::<TestVec>()
|
|
.0
|
|
.push("OrdB hook on_remove");
|
|
}
|
|
|
|
fn ord_b_observer_on_add(_trigger: Trigger<OnAdd, OrdB>, mut res: ResMut<TestVec>) {
|
|
res.0.push("OrdB observer on_add");
|
|
}
|
|
|
|
fn ord_b_observer_on_insert(_trigger: Trigger<OnInsert, OrdB>, mut res: ResMut<TestVec>) {
|
|
res.0.push("OrdB observer on_insert");
|
|
}
|
|
|
|
fn ord_b_observer_on_replace(_trigger: Trigger<OnReplace, OrdB>, mut res: ResMut<TestVec>) {
|
|
res.0.push("OrdB observer on_replace");
|
|
}
|
|
|
|
fn ord_b_observer_on_remove(_trigger: Trigger<OnRemove, OrdB>, mut res: ResMut<TestVec>) {
|
|
res.0.push("OrdB observer on_remove");
|
|
}
|
|
|
|
#[test]
|
|
fn command_ordering_is_correct() {
|
|
let mut world = World::new();
|
|
world.insert_resource(TestVec(Vec::new()));
|
|
world.add_observer(ord_a_observer_on_add);
|
|
world.add_observer(ord_a_observer_on_insert);
|
|
world.add_observer(ord_a_observer_on_replace);
|
|
world.add_observer(ord_a_observer_on_remove);
|
|
world.add_observer(ord_b_observer_on_add);
|
|
world.add_observer(ord_b_observer_on_insert);
|
|
world.add_observer(ord_b_observer_on_replace);
|
|
world.add_observer(ord_b_observer_on_remove);
|
|
let _entity = world.spawn(OrdA).id();
|
|
let expected = [
|
|
"OrdA hook on_add", // adds command to insert OrdB
|
|
"OrdA observer on_add",
|
|
"OrdA hook on_insert", // adds command to despawn entity
|
|
"OrdA observer on_insert",
|
|
"OrdB hook on_add", // adds command to just add to this log
|
|
"OrdB observer on_add",
|
|
"OrdB hook on_insert",
|
|
"OrdB observer on_insert",
|
|
"OrdB command on_add", // command added by OrdB hook on_add, needs to run before despawn command
|
|
"OrdA observer on_replace", // start of despawn
|
|
"OrdA hook on_replace",
|
|
"OrdA observer on_remove",
|
|
"OrdA hook on_remove",
|
|
"OrdB observer on_replace",
|
|
"OrdB hook on_replace",
|
|
"OrdB observer on_remove",
|
|
"OrdB hook on_remove",
|
|
];
|
|
world.flush();
|
|
assert_eq!(world.resource_mut::<TestVec>().0.as_slice(), &expected[..]);
|
|
}
|
|
|
|
#[test]
|
|
fn entity_world_mut_clone_and_move_components() {
|
|
#[derive(Component, Clone, PartialEq, Debug)]
|
|
struct A;
|
|
|
|
#[derive(Component, Clone, PartialEq, Debug)]
|
|
struct B;
|
|
|
|
#[derive(Component, Clone, PartialEq, Debug)]
|
|
struct C(u32);
|
|
|
|
#[derive(Component, Clone, PartialEq, Debug, Default)]
|
|
struct D;
|
|
|
|
let mut world = World::new();
|
|
let entity_a = world.spawn((A, B, C(5))).id();
|
|
let entity_b = world.spawn((A, C(4))).id();
|
|
|
|
world.entity_mut(entity_a).clone_components::<B>(entity_b);
|
|
assert_eq!(world.entity(entity_a).get::<B>(), Some(&B));
|
|
assert_eq!(world.entity(entity_b).get::<B>(), Some(&B));
|
|
|
|
world.entity_mut(entity_a).move_components::<C>(entity_b);
|
|
assert_eq!(world.entity(entity_a).get::<C>(), None);
|
|
assert_eq!(world.entity(entity_b).get::<C>(), Some(&C(5)));
|
|
|
|
assert_eq!(world.entity(entity_a).get::<A>(), Some(&A));
|
|
assert_eq!(world.entity(entity_b).get::<A>(), Some(&A));
|
|
}
|
|
|
|
#[test]
|
|
fn entity_world_mut_clone_with_move_and_require() {
|
|
#[derive(Component, Clone, PartialEq, Debug)]
|
|
#[require(B)]
|
|
struct A;
|
|
|
|
#[derive(Component, Clone, PartialEq, Debug, Default)]
|
|
#[require(C(3))]
|
|
struct B;
|
|
|
|
#[derive(Component, Clone, PartialEq, Debug, Default)]
|
|
#[require(D)]
|
|
struct C(u32);
|
|
|
|
#[derive(Component, Clone, PartialEq, Debug, Default)]
|
|
struct D;
|
|
|
|
let mut world = World::new();
|
|
let entity_a = world.spawn(A).id();
|
|
let entity_b = world.spawn_empty().id();
|
|
|
|
world.entity_mut(entity_a).clone_with(entity_b, |builder| {
|
|
builder
|
|
.move_components(true)
|
|
.without_required_components(|builder| {
|
|
builder.deny::<A>();
|
|
});
|
|
});
|
|
|
|
assert_eq!(world.entity(entity_a).get::<A>(), Some(&A));
|
|
assert_eq!(world.entity(entity_b).get::<A>(), None);
|
|
|
|
assert_eq!(world.entity(entity_a).get::<B>(), None);
|
|
assert_eq!(world.entity(entity_b).get::<B>(), Some(&B));
|
|
|
|
assert_eq!(world.entity(entity_a).get::<C>(), None);
|
|
assert_eq!(world.entity(entity_b).get::<C>(), Some(&C(3)));
|
|
|
|
assert_eq!(world.entity(entity_a).get::<D>(), None);
|
|
assert_eq!(world.entity(entity_b).get::<D>(), Some(&D));
|
|
}
|
|
|
|
#[test]
|
|
fn update_despawned_by_after_observers() {
|
|
let mut world = World::new();
|
|
|
|
#[derive(Component)]
|
|
#[component(on_remove = get_tracked)]
|
|
struct C;
|
|
|
|
static TRACKED: OnceLock<MaybeLocation> = OnceLock::new();
|
|
fn get_tracked(world: DeferredWorld, HookContext { entity, .. }: HookContext) {
|
|
TRACKED.get_or_init(|| {
|
|
world
|
|
.entities
|
|
.entity_get_spawned_or_despawned_by(entity)
|
|
.map(|l| l.unwrap())
|
|
});
|
|
}
|
|
|
|
#[track_caller]
|
|
fn caller_spawn(world: &mut World) -> (Entity, MaybeLocation) {
|
|
let caller = MaybeLocation::caller();
|
|
(world.spawn(C).id(), caller)
|
|
}
|
|
let (entity, spawner) = caller_spawn(&mut world);
|
|
|
|
assert_eq!(
|
|
spawner,
|
|
world
|
|
.entities()
|
|
.entity_get_spawned_or_despawned_by(entity)
|
|
.map(|l| l.unwrap())
|
|
);
|
|
|
|
#[track_caller]
|
|
fn caller_despawn(world: &mut World, entity: Entity) -> MaybeLocation {
|
|
world.despawn(entity);
|
|
MaybeLocation::caller()
|
|
}
|
|
let despawner = caller_despawn(&mut world, entity);
|
|
|
|
assert_eq!(spawner, *TRACKED.get().unwrap());
|
|
assert_eq!(
|
|
despawner,
|
|
world
|
|
.entities()
|
|
.entity_get_spawned_or_despawned_by(entity)
|
|
.map(|l| l.unwrap())
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn with_component_activates_hooks() {
|
|
use core::sync::atomic::{AtomicBool, AtomicU8, Ordering};
|
|
|
|
#[derive(Component, PartialEq, Eq, Debug)]
|
|
#[component(immutable)]
|
|
struct Foo(bool);
|
|
|
|
static EXPECTED_VALUE: AtomicBool = AtomicBool::new(false);
|
|
|
|
static ADD_COUNT: AtomicU8 = AtomicU8::new(0);
|
|
static REMOVE_COUNT: AtomicU8 = AtomicU8::new(0);
|
|
static REPLACE_COUNT: AtomicU8 = AtomicU8::new(0);
|
|
static INSERT_COUNT: AtomicU8 = AtomicU8::new(0);
|
|
|
|
let mut world = World::default();
|
|
|
|
world.register_component::<Foo>();
|
|
world
|
|
.register_component_hooks::<Foo>()
|
|
.on_add(|world, context| {
|
|
ADD_COUNT.fetch_add(1, Ordering::Relaxed);
|
|
|
|
assert_eq!(
|
|
world.get(context.entity),
|
|
Some(&Foo(EXPECTED_VALUE.load(Ordering::Relaxed)))
|
|
);
|
|
})
|
|
.on_remove(|world, context| {
|
|
REMOVE_COUNT.fetch_add(1, Ordering::Relaxed);
|
|
|
|
assert_eq!(
|
|
world.get(context.entity),
|
|
Some(&Foo(EXPECTED_VALUE.load(Ordering::Relaxed)))
|
|
);
|
|
})
|
|
.on_replace(|world, context| {
|
|
REPLACE_COUNT.fetch_add(1, Ordering::Relaxed);
|
|
|
|
assert_eq!(
|
|
world.get(context.entity),
|
|
Some(&Foo(EXPECTED_VALUE.load(Ordering::Relaxed)))
|
|
);
|
|
})
|
|
.on_insert(|world, context| {
|
|
INSERT_COUNT.fetch_add(1, Ordering::Relaxed);
|
|
|
|
assert_eq!(
|
|
world.get(context.entity),
|
|
Some(&Foo(EXPECTED_VALUE.load(Ordering::Relaxed)))
|
|
);
|
|
});
|
|
|
|
let entity = world.spawn(Foo(false)).id();
|
|
|
|
assert_eq!(ADD_COUNT.load(Ordering::Relaxed), 1);
|
|
assert_eq!(REMOVE_COUNT.load(Ordering::Relaxed), 0);
|
|
assert_eq!(REPLACE_COUNT.load(Ordering::Relaxed), 0);
|
|
assert_eq!(INSERT_COUNT.load(Ordering::Relaxed), 1);
|
|
|
|
let mut entity = world.entity_mut(entity);
|
|
|
|
let archetype_pointer_before = &raw const *entity.archetype();
|
|
|
|
assert_eq!(entity.get::<Foo>(), Some(&Foo(false)));
|
|
|
|
entity.modify_component(|foo: &mut Foo| {
|
|
foo.0 = true;
|
|
EXPECTED_VALUE.store(foo.0, Ordering::Relaxed);
|
|
});
|
|
|
|
let archetype_pointer_after = &raw const *entity.archetype();
|
|
|
|
assert_eq!(entity.get::<Foo>(), Some(&Foo(true)));
|
|
|
|
assert_eq!(ADD_COUNT.load(Ordering::Relaxed), 1);
|
|
assert_eq!(REMOVE_COUNT.load(Ordering::Relaxed), 0);
|
|
assert_eq!(REPLACE_COUNT.load(Ordering::Relaxed), 1);
|
|
assert_eq!(INSERT_COUNT.load(Ordering::Relaxed), 2);
|
|
|
|
assert_eq!(archetype_pointer_before, archetype_pointer_after);
|
|
}
|
|
|
|
#[test]
|
|
fn bundle_remove_only_triggers_for_present_components() {
|
|
let mut world = World::default();
|
|
|
|
#[derive(Component)]
|
|
struct A;
|
|
|
|
#[derive(Component)]
|
|
struct B;
|
|
|
|
#[derive(Resource, PartialEq, Eq, Debug)]
|
|
struct Tracker {
|
|
a: bool,
|
|
b: bool,
|
|
}
|
|
|
|
world.insert_resource(Tracker { a: false, b: false });
|
|
let entity = world.spawn(A).id();
|
|
|
|
world.add_observer(|_: Trigger<OnRemove, A>, mut tracker: ResMut<Tracker>| {
|
|
tracker.a = true;
|
|
});
|
|
world.add_observer(|_: Trigger<OnRemove, B>, mut tracker: ResMut<Tracker>| {
|
|
tracker.b = true;
|
|
});
|
|
|
|
world.entity_mut(entity).remove::<(A, B)>();
|
|
|
|
assert_eq!(
|
|
world.resource::<Tracker>(),
|
|
&Tracker {
|
|
a: true,
|
|
// The entity didn't have a B component, so it should not have been triggered.
|
|
b: false,
|
|
}
|
|
);
|
|
}
|
|
}
|