mirror of
https://github.com/bevyengine/bevy
synced 2024-12-23 19:43:07 +00:00
483f2464a8
# Objective - There were a few typos in the project. - This PR fixes these typos. ## Solution - Fixing the typos. Signed-off-by: SADIK KUZU <sadikkuzu@hotmail.com>
1688 lines
60 KiB
Rust
1688 lines
60 KiB
Rust
use crate::{
|
|
archetype::{Archetype, ArchetypeId, Archetypes},
|
|
bundle::{Bundle, BundleInfo, BundleInserter, DynamicBundle},
|
|
change_detection::MutUntyped,
|
|
component::{Component, ComponentId, ComponentTicks, Components, StorageType},
|
|
entity::{Entities, Entity, EntityLocation},
|
|
removal_detection::RemovedComponentEvents,
|
|
storage::Storages,
|
|
world::{Mut, World},
|
|
};
|
|
use bevy_ptr::{OwningPtr, Ptr};
|
|
use bevy_utils::tracing::debug;
|
|
use std::any::TypeId;
|
|
|
|
use super::{unsafe_world_cell::UnsafeEntityCell, Ref};
|
|
|
|
/// 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>(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.0.id()
|
|
}
|
|
|
|
/// Gets metadata indicating the location where the current entity is stored.
|
|
#[inline]
|
|
pub fn location(&self) -> EntityLocation {
|
|
self.0.location()
|
|
}
|
|
|
|
/// Returns the archetype that the current entity belongs to.
|
|
#[inline]
|
|
pub fn archetype(&self) -> &Archetype {
|
|
self.0.archetype()
|
|
}
|
|
|
|
/// Returns `true` if the current entity has a component of type `T`.
|
|
/// Otherwise, this returns `false`.
|
|
///
|
|
/// ## Notes
|
|
///
|
|
/// If you do not know the concrete type of a component, consider using
|
|
/// [`Self::contains_id`] or [`Self::contains_type_id`].
|
|
#[inline]
|
|
pub fn contains<T: Component>(&self) -> bool {
|
|
self.contains_type_id(TypeId::of::<T>())
|
|
}
|
|
|
|
/// Returns `true` if the current entity has a component identified by `component_id`.
|
|
/// Otherwise, this returns false.
|
|
///
|
|
/// ## Notes
|
|
///
|
|
/// - If you know the concrete type of the component, you should prefer [`Self::contains`].
|
|
/// - If you know the component's [`TypeId`] but not its [`ComponentId`], consider using
|
|
/// [`Self::contains_type_id`].
|
|
#[inline]
|
|
pub fn contains_id(&self, component_id: ComponentId) -> bool {
|
|
self.0.contains_id(component_id)
|
|
}
|
|
|
|
/// Returns `true` if the current entity has a component with the type identified by `type_id`.
|
|
/// Otherwise, this returns false.
|
|
///
|
|
/// ## Notes
|
|
///
|
|
/// - If you know the concrete type of the component, you should prefer [`Self::contains`].
|
|
/// - If you have a [`ComponentId`] instead of a [`TypeId`], consider using [`Self::contains_id`].
|
|
#[inline]
|
|
pub fn contains_type_id(&self, type_id: TypeId) -> bool {
|
|
self.0.contains_type_id(type_id)
|
|
}
|
|
|
|
/// Gets access to the component of type `T` for the current entity.
|
|
/// Returns `None` if the entity does not have a component of type `T`.
|
|
#[inline]
|
|
pub fn get<T: Component>(&self) -> Option<&'w T> {
|
|
// SAFETY: We have read-only access to all components of this entity.
|
|
unsafe { self.0.get::<T>() }
|
|
}
|
|
|
|
/// Gets access to the component of type `T` for the current entity,
|
|
/// 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.0.get_ref::<T>() }
|
|
}
|
|
|
|
/// Retrieves the change ticks for the given component. This can be useful for implementing change
|
|
/// detection in custom runtimes.
|
|
#[inline]
|
|
pub fn get_change_ticks<T: Component>(&self) -> Option<ComponentTicks> {
|
|
// SAFETY: We have read-only access to all components of this entity.
|
|
unsafe { self.0.get_change_ticks::<T>() }
|
|
}
|
|
|
|
/// Retrieves the change ticks for the given [`ComponentId`]. This can be useful for implementing change
|
|
/// 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.0.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 where possible and only
|
|
/// use this in cases where the actual component types are not known at
|
|
/// compile time.**
|
|
///
|
|
/// Unlike [`EntityRef::get`], this returns a raw pointer to the component,
|
|
/// which is only valid while the `'w` borrow of the lifetime is active.
|
|
#[inline]
|
|
pub fn get_by_id(&self, component_id: ComponentId) -> Option<Ptr<'w>> {
|
|
// SAFETY: We have read-only access to all components of this entity.
|
|
unsafe { self.0.get_by_id(component_id) }
|
|
}
|
|
}
|
|
|
|
impl<'w> From<EntityWorldMut<'w>> for EntityRef<'w> {
|
|
fn from(entity_mut: EntityWorldMut<'w>) -> EntityRef<'w> {
|
|
// SAFETY:
|
|
// - `EntityWorldMut` guarantees exclusive access to the entire world.
|
|
unsafe { EntityRef::new(entity_mut.into_unsafe_entity_cell()) }
|
|
}
|
|
}
|
|
|
|
impl<'a> From<&'a EntityWorldMut<'_>> for EntityRef<'a> {
|
|
fn from(value: &'a EntityWorldMut<'_>) -> Self {
|
|
// SAFETY:
|
|
// - `EntityWorldMut` guarantees exclusive access to the entire world.
|
|
// - `&value` ensures no mutable accesses are active.
|
|
unsafe { EntityRef::new(value.as_unsafe_entity_cell_readonly()) }
|
|
}
|
|
}
|
|
|
|
impl<'w> From<EntityMut<'w>> for EntityRef<'w> {
|
|
fn from(value: EntityMut<'w>) -> Self {
|
|
// SAFETY:
|
|
// - `EntityMut` guarantees exclusive access to all of the entity's components.
|
|
unsafe { EntityRef::new(value.0) }
|
|
}
|
|
}
|
|
|
|
impl<'a> From<&'a EntityMut<'_>> for EntityRef<'a> {
|
|
fn from(value: &'a EntityMut<'_>) -> Self {
|
|
// SAFETY:
|
|
// - `EntityMut` guarantees exclusive access to all of the entity's components.
|
|
// - `&value` ensures there are no mutable accesses.
|
|
unsafe { EntityRef::new(value.0) }
|
|
}
|
|
}
|
|
|
|
/// Provides mutable access to a single entity and all of its components.
|
|
///
|
|
/// Contrast with [`EntityWorldMut`], with allows adding and removing components,
|
|
/// despawning the entity, and provides mutable access to the entire world.
|
|
/// Because of this, `EntityWorldMut` cannot coexist with any other world accesses.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// Disjoint mutable access.
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// # #[derive(Component)] pub struct A;
|
|
/// fn disjoint_system(
|
|
/// query1: Query<EntityMut, With<A>>,
|
|
/// query2: Query<EntityMut, Without<A>>,
|
|
/// ) {
|
|
/// // ...
|
|
/// }
|
|
/// # bevy_ecs::system::assert_is_system(disjoint_system);
|
|
/// ```
|
|
pub struct EntityMut<'w>(UnsafeEntityCell<'w>);
|
|
|
|
impl<'w> EntityMut<'w> {
|
|
/// # Safety
|
|
/// - `cell` must have permission to mutate every component of the entity.
|
|
/// - No accesses to any of the entity's components may exist
|
|
/// at the same time as the returned [`EntityMut`].
|
|
pub(crate) unsafe fn new(cell: UnsafeEntityCell<'w>) -> Self {
|
|
Self(cell)
|
|
}
|
|
|
|
/// Returns a new instance with a shorter lifetime.
|
|
/// This is useful if you have `&mut EntityMut`, but you need `EntityMut`.
|
|
pub fn reborrow(&mut self) -> EntityMut<'_> {
|
|
// SAFETY: We have exclusive access to the entire entity and its components.
|
|
unsafe { Self::new(self.0) }
|
|
}
|
|
|
|
/// Gets read-only access to all of the entity's components.
|
|
pub fn as_readonly(&self) -> EntityRef<'_> {
|
|
EntityRef::from(self)
|
|
}
|
|
|
|
/// Returns the [ID](Entity) of the current entity.
|
|
#[inline]
|
|
#[must_use = "Omit the .id() call if you do not need to store the `Entity` identifier."]
|
|
pub fn id(&self) -> Entity {
|
|
self.0.id()
|
|
}
|
|
|
|
/// Gets metadata indicating the location where the current entity is stored.
|
|
#[inline]
|
|
pub fn location(&self) -> EntityLocation {
|
|
self.0.location()
|
|
}
|
|
|
|
/// Returns the archetype that the current entity belongs to.
|
|
#[inline]
|
|
pub fn archetype(&self) -> &Archetype {
|
|
self.0.archetype()
|
|
}
|
|
|
|
/// Returns `true` if the current entity has a component of type `T`.
|
|
/// Otherwise, this returns `false`.
|
|
///
|
|
/// ## Notes
|
|
///
|
|
/// If you do not know the concrete type of a component, consider using
|
|
/// [`Self::contains_id`] or [`Self::contains_type_id`].
|
|
#[inline]
|
|
pub fn contains<T: Component>(&self) -> bool {
|
|
self.contains_type_id(TypeId::of::<T>())
|
|
}
|
|
|
|
/// Returns `true` if the current entity has a component identified by `component_id`.
|
|
/// Otherwise, this returns false.
|
|
///
|
|
/// ## Notes
|
|
///
|
|
/// - If you know the concrete type of the component, you should prefer [`Self::contains`].
|
|
/// - If you know the component's [`TypeId`] but not its [`ComponentId`], consider using
|
|
/// [`Self::contains_type_id`].
|
|
#[inline]
|
|
pub fn contains_id(&self, component_id: ComponentId) -> bool {
|
|
self.0.contains_id(component_id)
|
|
}
|
|
|
|
/// Returns `true` if the current entity has a component with the type identified by `type_id`.
|
|
/// Otherwise, this returns false.
|
|
///
|
|
/// ## Notes
|
|
///
|
|
/// - If you know the concrete type of the component, you should prefer [`Self::contains`].
|
|
/// - If you have a [`ComponentId`] instead of a [`TypeId`], consider using [`Self::contains_id`].
|
|
#[inline]
|
|
pub fn contains_type_id(&self, type_id: TypeId) -> bool {
|
|
self.0.contains_type_id(type_id)
|
|
}
|
|
|
|
/// Gets access to the component of type `T` for the current entity.
|
|
/// Returns `None` if the entity does not have a component of type `T`.
|
|
#[inline]
|
|
pub fn get<T: Component>(&self) -> Option<&'_ T> {
|
|
self.as_readonly().get()
|
|
}
|
|
|
|
/// Gets access to the component of type `T` for the current entity,
|
|
/// including change detection information as a [`Ref`].
|
|
///
|
|
/// Returns `None` if the entity does not have a component of type `T`.
|
|
#[inline]
|
|
pub fn get_ref<T: Component>(&self) -> Option<Ref<'_, T>> {
|
|
self.as_readonly().get_ref()
|
|
}
|
|
|
|
/// Gets mutable access to the component of type `T` for the current entity.
|
|
/// Returns `None` if the entity does not have a component of type `T`.
|
|
#[inline]
|
|
pub fn get_mut<T: Component>(&mut self) -> Option<Mut<'_, T>> {
|
|
// SAFETY: &mut self implies exclusive access for duration of returned value
|
|
unsafe { self.0.get_mut() }
|
|
}
|
|
|
|
/// Retrieves the change ticks for the given component. This can be useful for implementing change
|
|
/// detection in custom runtimes.
|
|
#[inline]
|
|
pub fn get_change_ticks<T: Component>(&self) -> Option<ComponentTicks> {
|
|
self.as_readonly().get_change_ticks::<T>()
|
|
}
|
|
|
|
/// Retrieves the change ticks for the given [`ComponentId`]. This can be useful for implementing change
|
|
/// detection in custom runtimes.
|
|
///
|
|
/// **You should prefer to use the typed API [`EntityWorldMut::get_change_ticks`] where possible and only
|
|
/// use this in cases where the actual component types are not known at
|
|
/// compile time.**
|
|
#[inline]
|
|
pub fn get_change_ticks_by_id(&self, component_id: ComponentId) -> Option<ComponentTicks> {
|
|
self.as_readonly().get_change_ticks_by_id(component_id)
|
|
}
|
|
|
|
/// Gets the component of the given [`ComponentId`] from the entity.
|
|
///
|
|
/// **You should prefer to use the typed API [`EntityWorldMut::get`] where possible and only
|
|
/// use this in cases where the actual component types are not known at
|
|
/// compile time.**
|
|
///
|
|
/// Unlike [`EntityMut::get`], this returns a raw pointer to the component,
|
|
/// which is only valid while the [`EntityMut`] is alive.
|
|
#[inline]
|
|
pub fn get_by_id(&self, component_id: ComponentId) -> Option<Ptr<'_>> {
|
|
self.as_readonly().get_by_id(component_id)
|
|
}
|
|
|
|
/// Gets a [`MutUntyped`] of the component of the given [`ComponentId`] from the entity.
|
|
///
|
|
/// **You should prefer to use the typed API [`EntityMut::get_mut`] where possible and only
|
|
/// use this in cases where the actual component types are not known at
|
|
/// compile time.**
|
|
///
|
|
/// Unlike [`EntityMut::get_mut`], this returns a raw pointer to the component,
|
|
/// which is only valid while the [`EntityMut`] is alive.
|
|
#[inline]
|
|
pub fn get_mut_by_id(&mut self, component_id: ComponentId) -> Option<MutUntyped<'_>> {
|
|
// SAFETY:
|
|
// - `&mut self` ensures that no references exist to this entity's components.
|
|
// - `as_unsafe_world_cell` gives mutable permission for all components on this entity
|
|
unsafe { self.0.get_mut_by_id(component_id) }
|
|
}
|
|
}
|
|
|
|
impl<'w> From<EntityWorldMut<'w>> for EntityMut<'w> {
|
|
fn from(value: EntityWorldMut<'w>) -> Self {
|
|
// SAFETY: `EntityWorldMut` guarantees exclusive access to the entire world.
|
|
unsafe { EntityMut::new(value.into_unsafe_entity_cell()) }
|
|
}
|
|
}
|
|
|
|
impl<'a> From<&'a mut EntityWorldMut<'_>> for EntityMut<'a> {
|
|
fn from(value: &'a mut EntityWorldMut<'_>) -> Self {
|
|
// SAFETY: `EntityWorldMut` guarantees exclusive access to the entire world.
|
|
unsafe { EntityMut::new(value.as_unsafe_entity_cell()) }
|
|
}
|
|
}
|
|
|
|
/// A mutable reference to a particular [`Entity`], and the entire world.
|
|
/// This is essentially a performance-optimized `(Entity, &mut World)` tuple,
|
|
/// which caches the [`EntityLocation`] to reduce duplicate lookups.
|
|
///
|
|
/// Since this type provides mutable access to the entire world, only one
|
|
/// [`EntityWorldMut`] can exist at a time for a given world.
|
|
///
|
|
/// See also [`EntityMut`], which allows disjoint mutable access to multiple
|
|
/// entities at once. Unlike `EntityMut`, this type allows adding and
|
|
/// removing components, and despawning the entity.
|
|
pub struct EntityWorldMut<'w> {
|
|
world: &'w mut World,
|
|
entity: Entity,
|
|
location: EntityLocation,
|
|
}
|
|
|
|
impl<'w> EntityWorldMut<'w> {
|
|
fn as_unsafe_entity_cell_readonly(&self) -> UnsafeEntityCell<'_> {
|
|
UnsafeEntityCell::new(
|
|
self.world.as_unsafe_world_cell_readonly(),
|
|
self.entity,
|
|
self.location,
|
|
)
|
|
}
|
|
fn as_unsafe_entity_cell(&mut self) -> UnsafeEntityCell<'_> {
|
|
UnsafeEntityCell::new(
|
|
self.world.as_unsafe_world_cell(),
|
|
self.entity,
|
|
self.location,
|
|
)
|
|
}
|
|
fn into_unsafe_entity_cell(self) -> UnsafeEntityCell<'w> {
|
|
UnsafeEntityCell::new(
|
|
self.world.as_unsafe_world_cell(),
|
|
self.entity,
|
|
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,
|
|
}
|
|
}
|
|
|
|
/// 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.
|
|
#[inline]
|
|
pub fn location(&self) -> EntityLocation {
|
|
self.location
|
|
}
|
|
|
|
/// Returns the archetype that the current entity belongs to.
|
|
#[inline]
|
|
pub fn archetype(&self) -> &Archetype {
|
|
&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`].
|
|
#[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.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`].
|
|
#[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`.
|
|
#[inline]
|
|
pub fn get<T: Component>(&self) -> Option<&'_ T> {
|
|
EntityRef::from(self).get()
|
|
}
|
|
|
|
/// Gets access to the component of type `T` for the current entity,
|
|
/// including change detection information as a [`Ref`].
|
|
///
|
|
/// Returns `None` if the entity does not have a component of type `T`.
|
|
#[inline]
|
|
pub fn get_ref<T: Component>(&self) -> Option<Ref<'_, T>> {
|
|
EntityRef::from(self).get_ref()
|
|
}
|
|
|
|
/// Gets mutable access to the component of type `T` for the current entity.
|
|
/// Returns `None` if the entity does not have a component of type `T`.
|
|
#[inline]
|
|
pub fn get_mut<T: Component>(&mut self) -> Option<Mut<'_, T>> {
|
|
// SAFETY: &mut self implies exclusive access for duration of returned value
|
|
unsafe { self.as_unsafe_entity_cell().get_mut() }
|
|
}
|
|
|
|
/// Retrieves the change ticks for the given component. This can be useful for implementing change
|
|
/// detection in custom runtimes.
|
|
#[inline]
|
|
pub fn get_change_ticks<T: Component>(&self) -> Option<ComponentTicks> {
|
|
EntityRef::from(self).get_change_ticks::<T>()
|
|
}
|
|
|
|
/// Retrieves the change ticks for the given [`ComponentId`]. This can be useful for implementing change
|
|
/// detection in custom runtimes.
|
|
///
|
|
/// **You should prefer to use the typed API [`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> {
|
|
EntityRef::from(self).get_change_ticks_by_id(component_id)
|
|
}
|
|
|
|
/// Gets the component of the given [`ComponentId`] from the entity.
|
|
///
|
|
/// **You should prefer to use the typed API [`EntityWorldMut::get`] where possible and only
|
|
/// use this in cases where the actual component types are not known at
|
|
/// compile time.**
|
|
///
|
|
/// Unlike [`EntityWorldMut::get`], this returns a raw pointer to the component,
|
|
/// which is only valid while the [`EntityWorldMut`] is alive.
|
|
#[inline]
|
|
pub fn get_by_id(&self, component_id: ComponentId) -> Option<Ptr<'_>> {
|
|
EntityRef::from(self).get_by_id(component_id)
|
|
}
|
|
|
|
/// Gets a [`MutUntyped`] of the component of the given [`ComponentId`] from the entity.
|
|
///
|
|
/// **You should prefer to use the typed API [`EntityWorldMut::get_mut`] where possible and only
|
|
/// use this in cases where the actual component types are not known at
|
|
/// compile time.**
|
|
///
|
|
/// Unlike [`EntityWorldMut::get_mut`], this returns a raw pointer to the component,
|
|
/// which is only valid while the [`EntityWorldMut`] is alive.
|
|
#[inline]
|
|
pub fn get_mut_by_id(&mut self, component_id: ComponentId) -> Option<MutUntyped<'_>> {
|
|
// SAFETY:
|
|
// - `&mut self` ensures that no references exist to this entity's components.
|
|
// - `as_unsafe_world_cell` gives mutable permission for all components on this entity
|
|
unsafe { self.as_unsafe_entity_cell().get_mut_by_id(component_id) }
|
|
}
|
|
|
|
/// Adds a [`Bundle`] of components to the entity.
|
|
///
|
|
/// This will overwrite any previous value(s) of the same component type.
|
|
pub fn insert<T: Bundle>(&mut self, bundle: T) -> &mut Self {
|
|
let change_tick = self.world.change_tick();
|
|
let bundle_info = self
|
|
.world
|
|
.bundles
|
|
.init_info::<T>(&mut self.world.components, &mut self.world.storages);
|
|
let mut bundle_inserter = bundle_info.get_bundle_inserter(
|
|
&mut self.world.entities,
|
|
&mut self.world.archetypes,
|
|
&self.world.components,
|
|
&mut self.world.storages,
|
|
self.location.archetype_id,
|
|
change_tick,
|
|
);
|
|
// SAFETY: location matches current entity. `T` matches `bundle_info`
|
|
unsafe {
|
|
self.location = bundle_inserter.insert(self.entity, self.location, bundle);
|
|
}
|
|
|
|
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`]
|
|
pub unsafe fn insert_by_id(
|
|
&mut self,
|
|
component_id: ComponentId,
|
|
component: OwningPtr<'_>,
|
|
) -> &mut Self {
|
|
let change_tick = self.world.change_tick();
|
|
|
|
let bundles = &mut self.world.bundles;
|
|
let components = &mut self.world.components;
|
|
|
|
let (bundle_info, storage_type) = bundles.init_component_info(components, component_id);
|
|
let bundle_inserter = bundle_info.get_bundle_inserter(
|
|
&mut self.world.entities,
|
|
&mut self.world.archetypes,
|
|
&self.world.components,
|
|
&mut self.world.storages,
|
|
self.location.archetype_id,
|
|
change_tick,
|
|
);
|
|
|
|
self.location = insert_dynamic_bundle(
|
|
bundle_inserter,
|
|
self.entity,
|
|
self.location,
|
|
Some(component).into_iter(),
|
|
Some(storage_type).into_iter(),
|
|
);
|
|
|
|
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`]
|
|
pub unsafe fn insert_by_ids<'a, I: Iterator<Item = OwningPtr<'a>>>(
|
|
&mut self,
|
|
component_ids: &[ComponentId],
|
|
iter_components: I,
|
|
) -> &mut Self {
|
|
let change_tick = self.world.change_tick();
|
|
|
|
let bundles = &mut self.world.bundles;
|
|
let components = &mut self.world.components;
|
|
|
|
let (bundle_info, storage_types) = bundles.init_dynamic_info(components, component_ids);
|
|
let bundle_inserter = bundle_info.get_bundle_inserter(
|
|
&mut self.world.entities,
|
|
&mut self.world.archetypes,
|
|
&self.world.components,
|
|
&mut self.world.storages,
|
|
self.location.archetype_id,
|
|
change_tick,
|
|
);
|
|
|
|
self.location = insert_dynamic_bundle(
|
|
bundle_inserter,
|
|
self.entity,
|
|
self.location,
|
|
iter_components,
|
|
storage_types.iter().cloned(),
|
|
);
|
|
|
|
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.
|
|
// TODO: BundleRemover?
|
|
#[must_use]
|
|
pub fn take<T: Bundle>(&mut self) -> Option<T> {
|
|
let archetypes = &mut self.world.archetypes;
|
|
let storages = &mut self.world.storages;
|
|
let components = &mut self.world.components;
|
|
let entities = &mut self.world.entities;
|
|
let removed_components = &mut self.world.removed_components;
|
|
|
|
let bundle_info = self.world.bundles.init_info::<T>(components, storages);
|
|
let old_location = self.location;
|
|
// SAFETY: `archetype_id` exists because it is referenced in the old `EntityLocation` which is valid,
|
|
// components exist in `bundle_info` because `Bundles::init_info` initializes a `BundleInfo` containing all components of the bundle type `T`
|
|
let new_archetype_id = unsafe {
|
|
remove_bundle_from_archetype(
|
|
archetypes,
|
|
storages,
|
|
components,
|
|
old_location.archetype_id,
|
|
bundle_info,
|
|
false,
|
|
)?
|
|
};
|
|
|
|
if new_archetype_id == old_location.archetype_id {
|
|
return None;
|
|
}
|
|
|
|
let mut bundle_components = bundle_info.components().iter().cloned();
|
|
let entity = self.entity;
|
|
// SAFETY: bundle components are iterated in order, which guarantees that the component type
|
|
// matches
|
|
let result = unsafe {
|
|
T::from_components(storages, &mut |storages| {
|
|
let component_id = bundle_components.next().unwrap();
|
|
// SAFETY:
|
|
// - entity location is valid
|
|
// - table row is removed below, without dropping the contents
|
|
// - `components` comes from the same world as `storages`
|
|
take_component(
|
|
storages,
|
|
components,
|
|
removed_components,
|
|
component_id,
|
|
entity,
|
|
old_location,
|
|
)
|
|
})
|
|
};
|
|
|
|
#[allow(clippy::undocumented_unsafe_blocks)] // TODO: document why this is safe
|
|
unsafe {
|
|
Self::move_entity_from_remove::<false>(
|
|
entity,
|
|
&mut self.location,
|
|
old_location.archetype_id,
|
|
old_location,
|
|
entities,
|
|
archetypes,
|
|
storages,
|
|
new_archetype_id,
|
|
);
|
|
}
|
|
|
|
Some(result)
|
|
}
|
|
|
|
/// Safety: `new_archetype_id` must have the same or a subset of the components
|
|
/// in `old_archetype_id`. Probably more safety stuff too, audit a call to
|
|
/// this fn as if the code here was written inline
|
|
///
|
|
/// when DROP is true removed components will be dropped otherwise they will be forgotten
|
|
///
|
|
// We use a const generic here so that we are less reliant on
|
|
// inlining for rustc to optimize out the `match DROP`
|
|
#[allow(clippy::too_many_arguments)]
|
|
unsafe fn move_entity_from_remove<const DROP: bool>(
|
|
entity: Entity,
|
|
self_location: &mut EntityLocation,
|
|
old_archetype_id: ArchetypeId,
|
|
old_location: EntityLocation,
|
|
entities: &mut Entities,
|
|
archetypes: &mut Archetypes,
|
|
storages: &mut Storages,
|
|
new_archetype_id: ArchetypeId,
|
|
) {
|
|
let old_archetype = &mut archetypes[old_archetype_id];
|
|
let remove_result = old_archetype.swap_remove(old_location.archetype_row);
|
|
// if an entity was moved into this entity's archetype row, update its archetype row
|
|
if let Some(swapped_entity) = remove_result.swapped_entity {
|
|
let swapped_location = entities.get(swapped_entity).unwrap();
|
|
|
|
entities.set(
|
|
swapped_entity.index(),
|
|
EntityLocation {
|
|
archetype_id: swapped_location.archetype_id,
|
|
archetype_row: old_location.archetype_row,
|
|
table_id: swapped_location.table_id,
|
|
table_row: swapped_location.table_row,
|
|
},
|
|
);
|
|
}
|
|
let old_table_row = remove_result.table_row;
|
|
let old_table_id = old_archetype.table_id();
|
|
let new_archetype = &mut archetypes[new_archetype_id];
|
|
|
|
let new_location = if old_table_id == new_archetype.table_id() {
|
|
new_archetype.allocate(entity, old_table_row)
|
|
} else {
|
|
let (old_table, new_table) = storages
|
|
.tables
|
|
.get_2_mut(old_table_id, new_archetype.table_id());
|
|
|
|
// SAFETY: old_table_row exists
|
|
let move_result = if DROP {
|
|
old_table.move_to_and_drop_missing_unchecked(old_table_row, new_table)
|
|
} else {
|
|
old_table.move_to_and_forget_missing_unchecked(old_table_row, new_table)
|
|
};
|
|
|
|
// SAFETY: move_result.new_row is a valid position in new_archetype's table
|
|
let new_location = new_archetype.allocate(entity, move_result.new_row);
|
|
|
|
// if an entity was moved into this entity's table row, update its table row
|
|
if let Some(swapped_entity) = move_result.swapped_entity {
|
|
let swapped_location = entities.get(swapped_entity).unwrap();
|
|
|
|
entities.set(
|
|
swapped_entity.index(),
|
|
EntityLocation {
|
|
archetype_id: swapped_location.archetype_id,
|
|
archetype_row: swapped_location.archetype_row,
|
|
table_id: swapped_location.table_id,
|
|
table_row: old_location.table_row,
|
|
},
|
|
);
|
|
archetypes[swapped_location.archetype_id]
|
|
.set_entity_table_row(swapped_location.archetype_row, old_table_row);
|
|
}
|
|
|
|
new_location
|
|
};
|
|
|
|
*self_location = new_location;
|
|
// SAFETY: The entity is valid and has been moved to the new location already.
|
|
entities.set(entity.index(), new_location);
|
|
}
|
|
|
|
/// Removes any components in the [`Bundle`] from the entity.
|
|
// TODO: BundleRemover?
|
|
pub fn remove<T: Bundle>(&mut self) -> &mut Self {
|
|
let archetypes = &mut self.world.archetypes;
|
|
let storages = &mut self.world.storages;
|
|
let components = &mut self.world.components;
|
|
let entities = &mut self.world.entities;
|
|
let removed_components = &mut self.world.removed_components;
|
|
|
|
let bundle_info = self.world.bundles.init_info::<T>(components, storages);
|
|
let old_location = self.location;
|
|
|
|
// SAFETY: `archetype_id` exists because it is referenced in the old `EntityLocation` which is valid,
|
|
// components exist in `bundle_info` because `Bundles::init_info` initializes a `BundleInfo` containing all components of the bundle type `T`
|
|
let new_archetype_id = unsafe {
|
|
remove_bundle_from_archetype(
|
|
archetypes,
|
|
storages,
|
|
components,
|
|
old_location.archetype_id,
|
|
bundle_info,
|
|
true,
|
|
)
|
|
.expect("intersections should always return a result")
|
|
};
|
|
|
|
if new_archetype_id == old_location.archetype_id {
|
|
return self;
|
|
}
|
|
|
|
let old_archetype = &mut archetypes[old_location.archetype_id];
|
|
let entity = self.entity;
|
|
for component_id in bundle_info.components().iter().cloned() {
|
|
if old_archetype.contains(component_id) {
|
|
removed_components.send(component_id, entity);
|
|
|
|
// Make sure to drop components stored in sparse sets.
|
|
// Dense components are dropped later in `move_to_and_drop_missing_unchecked`.
|
|
if let Some(StorageType::SparseSet) = old_archetype.get_storage_type(component_id) {
|
|
storages
|
|
.sparse_sets
|
|
.get_mut(component_id)
|
|
.unwrap()
|
|
.remove(entity);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[allow(clippy::undocumented_unsafe_blocks)] // TODO: document why this is safe
|
|
unsafe {
|
|
Self::move_entity_from_remove::<true>(
|
|
entity,
|
|
&mut self.location,
|
|
old_location.archetype_id,
|
|
old_location,
|
|
entities,
|
|
archetypes,
|
|
storages,
|
|
new_archetype_id,
|
|
);
|
|
}
|
|
|
|
self
|
|
}
|
|
|
|
/// Despawns the current entity.
|
|
pub fn despawn(self) {
|
|
debug!("Despawning entity {:?}", self.entity);
|
|
let world = self.world;
|
|
world.flush();
|
|
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[location.archetype_id];
|
|
for component_id in archetype.components() {
|
|
world.removed_components.send(component_id, self.entity);
|
|
}
|
|
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() {
|
|
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);
|
|
}
|
|
}
|
|
|
|
/// 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();
|
|
}
|
|
}
|
|
|
|
/// Inserts a dynamic [`Bundle`] into the entity.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// - [`OwningPtr`] and [`StorageType`] iterators must correspond to the
|
|
/// [`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,
|
|
) -> 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>
|
|
{
|
|
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) }
|
|
}
|
|
|
|
/// Removes a bundle from the given archetype and returns the resulting archetype (or None if the
|
|
/// removal was invalid). in the event that adding the given bundle does not result in an Archetype
|
|
/// change. Results are cached in the Archetype Graph to avoid redundant work.
|
|
/// if `intersection` is false, attempting to remove a bundle with components _not_ contained in the
|
|
/// current archetype will fail, returning None. if `intersection` is true, components in the bundle
|
|
/// but not in the current archetype will be ignored
|
|
///
|
|
/// # Safety
|
|
/// `archetype_id` must exist and components in `bundle_info` must exist
|
|
unsafe fn remove_bundle_from_archetype(
|
|
archetypes: &mut Archetypes,
|
|
storages: &mut Storages,
|
|
components: &Components,
|
|
archetype_id: ArchetypeId,
|
|
bundle_info: &BundleInfo,
|
|
intersection: bool,
|
|
) -> Option<ArchetypeId> {
|
|
// check the archetype graph to see if the Bundle has been removed from this archetype in the
|
|
// past
|
|
let remove_bundle_result = {
|
|
let edges = archetypes[archetype_id].edges();
|
|
if intersection {
|
|
edges.get_remove_bundle(bundle_info.id())
|
|
} else {
|
|
edges.get_take_bundle(bundle_info.id())
|
|
}
|
|
};
|
|
let result = if let Some(result) = remove_bundle_result {
|
|
// this Bundle removal result is cached. just return that!
|
|
result
|
|
} else {
|
|
let mut next_table_components;
|
|
let mut next_sparse_set_components;
|
|
let next_table_id;
|
|
{
|
|
let current_archetype = &mut archetypes[archetype_id];
|
|
let mut removed_table_components = Vec::new();
|
|
let mut removed_sparse_set_components = Vec::new();
|
|
for component_id in bundle_info.components().iter().cloned() {
|
|
if current_archetype.contains(component_id) {
|
|
// SAFETY: bundle components were already initialized by bundles.get_info
|
|
let component_info = components.get_info_unchecked(component_id);
|
|
match component_info.storage_type() {
|
|
StorageType::Table => removed_table_components.push(component_id),
|
|
StorageType::SparseSet => removed_sparse_set_components.push(component_id),
|
|
}
|
|
} else if !intersection {
|
|
// a component in the bundle was not present in the entity's archetype, so this
|
|
// removal is invalid cache the result in the archetype
|
|
// graph
|
|
current_archetype
|
|
.edges_mut()
|
|
.insert_take_bundle(bundle_info.id(), None);
|
|
return None;
|
|
}
|
|
}
|
|
|
|
// sort removed components so we can do an efficient "sorted remove". archetype
|
|
// components are already sorted
|
|
removed_table_components.sort();
|
|
removed_sparse_set_components.sort();
|
|
next_table_components = current_archetype.table_components().collect();
|
|
next_sparse_set_components = current_archetype.sparse_set_components().collect();
|
|
sorted_remove(&mut next_table_components, &removed_table_components);
|
|
sorted_remove(
|
|
&mut next_sparse_set_components,
|
|
&removed_sparse_set_components,
|
|
);
|
|
|
|
next_table_id = if removed_table_components.is_empty() {
|
|
current_archetype.table_id()
|
|
} else {
|
|
// SAFETY: all components in next_table_components exist
|
|
storages
|
|
.tables
|
|
.get_id_or_insert(&next_table_components, components)
|
|
};
|
|
}
|
|
|
|
let new_archetype_id = archetypes.get_id_or_insert(
|
|
next_table_id,
|
|
next_table_components,
|
|
next_sparse_set_components,
|
|
);
|
|
Some(new_archetype_id)
|
|
};
|
|
let current_archetype = &mut archetypes[archetype_id];
|
|
// cache the result in an edge
|
|
if intersection {
|
|
current_archetype
|
|
.edges_mut()
|
|
.insert_remove_bundle(bundle_info.id(), result);
|
|
} else {
|
|
current_archetype
|
|
.edges_mut()
|
|
.insert_take_bundle(bundle_info.id(), result);
|
|
}
|
|
result
|
|
}
|
|
|
|
fn sorted_remove<T: Eq + Ord + Copy>(source: &mut Vec<T>, remove: &[T]) {
|
|
let mut remove_index = 0;
|
|
source.retain(|value| {
|
|
while remove_index < remove.len() && *value > remove[remove_index] {
|
|
remove_index += 1;
|
|
}
|
|
|
|
if remove_index < remove.len() {
|
|
*value != remove[remove_index]
|
|
} else {
|
|
true
|
|
}
|
|
});
|
|
}
|
|
|
|
/// Moves component data out of storage.
|
|
///
|
|
/// This function leaves the underlying memory unchanged, but the component behind
|
|
/// returned pointer is semantically owned by the caller and will not be dropped in its original location.
|
|
/// Caller is responsible to drop component data behind returned pointer.
|
|
///
|
|
/// # Safety
|
|
/// - `location.table_row` must be in bounds of column of component id `component_id`
|
|
/// - `component_id` must be valid
|
|
/// - `components` must come from the same world as `self`
|
|
/// - The relevant table row **must be removed** by the caller once all components are taken, without dropping the value
|
|
#[inline]
|
|
pub(crate) unsafe fn take_component<'a>(
|
|
storages: &'a mut Storages,
|
|
components: &Components,
|
|
removed_components: &mut RemovedComponentEvents,
|
|
component_id: ComponentId,
|
|
entity: Entity,
|
|
location: EntityLocation,
|
|
) -> OwningPtr<'a> {
|
|
// SAFETY: caller promises component_id to be valid
|
|
let component_info = components.get_info_unchecked(component_id);
|
|
removed_components.send(component_id, entity);
|
|
match component_info.storage_type() {
|
|
StorageType::Table => {
|
|
let table = &mut storages.tables[location.table_id];
|
|
let components = table.get_column_mut(component_id).unwrap();
|
|
// SAFETY:
|
|
// - archetypes only store valid table_rows
|
|
// - index is in bounds as promised by caller
|
|
// - promote is safe because the caller promises to remove the table row without dropping it immediately afterwards
|
|
components
|
|
.get_data_unchecked_mut(location.table_row)
|
|
.promote()
|
|
}
|
|
StorageType::SparseSet => storages
|
|
.sparse_sets
|
|
.get_mut(component_id)
|
|
.unwrap()
|
|
.remove_and_forget(entity)
|
|
.unwrap(),
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use bevy_ptr::OwningPtr;
|
|
use std::panic::AssertUnwindSafe;
|
|
|
|
use crate::{self as bevy_ecs, component::ComponentId, prelude::*, system::assert_is_system};
|
|
|
|
#[test]
|
|
fn sorted_remove() {
|
|
let mut a = vec![1, 2, 3, 4, 5, 6, 7];
|
|
let b = vec![1, 2, 3, 5, 7];
|
|
super::sorted_remove(&mut a, &b);
|
|
|
|
assert_eq!(a, vec![4, 6]);
|
|
|
|
let mut a = vec![1];
|
|
let b = vec![1];
|
|
super::sorted_remove(&mut a, &b);
|
|
|
|
assert_eq!(a, vec![]);
|
|
|
|
let mut a = vec![1];
|
|
let b = vec![2];
|
|
super::sorted_remove(&mut a, &b);
|
|
|
|
assert_eq!(a, vec![1]);
|
|
}
|
|
|
|
#[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(std::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(std::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_none());
|
|
}
|
|
|
|
#[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_none());
|
|
assert!(entity.get_mut_by_id(invalid_component_id).is_none());
|
|
}
|
|
|
|
// 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!(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));
|
|
}
|
|
|
|
// 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.init_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.init_component::<TestComponent>();
|
|
let test_component_2_id = world.init_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);
|
|
}
|
|
|
|
#[derive(Component)]
|
|
struct A;
|
|
|
|
#[derive(Resource)]
|
|
struct R;
|
|
|
|
#[test]
|
|
fn disjoint_access() {
|
|
fn disjoint_readonly(_: Query<EntityMut, With<A>>, _: Query<EntityRef, Without<A>>) {}
|
|
|
|
fn disjoint_mutable(_: Query<EntityMut, With<A>>, _: Query<EntityMut, Without<A>>) {}
|
|
|
|
assert_is_system(disjoint_readonly);
|
|
assert_is_system(disjoint_mutable);
|
|
}
|
|
|
|
#[test]
|
|
fn ref_compatible() {
|
|
fn borrow_system(_: Query<(EntityRef, &A)>, _: Query<&A>) {}
|
|
|
|
assert_is_system(borrow_system);
|
|
}
|
|
|
|
#[test]
|
|
fn ref_compatible_with_resource() {
|
|
fn borrow_system(_: Query<EntityRef>, _: Res<R>) {}
|
|
|
|
assert_is_system(borrow_system);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore] // This should pass, but it currently fails due to limitations in our access model.
|
|
fn ref_compatible_with_resource_mut() {
|
|
fn borrow_system(_: Query<EntityRef>, _: ResMut<R>) {}
|
|
|
|
assert_is_system(borrow_system);
|
|
}
|
|
|
|
#[test]
|
|
#[should_panic]
|
|
fn ref_incompatible_with_mutable_component() {
|
|
fn incompatible_system(_: Query<(EntityRef, &mut A)>) {}
|
|
|
|
assert_is_system(incompatible_system);
|
|
}
|
|
|
|
#[test]
|
|
#[should_panic]
|
|
fn ref_incompatible_with_mutable_query() {
|
|
fn incompatible_system(_: Query<EntityRef>, _: Query<&mut A>) {}
|
|
|
|
assert_is_system(incompatible_system);
|
|
}
|
|
|
|
#[test]
|
|
fn mut_compatible_with_entity() {
|
|
fn borrow_mut_system(_: Query<(Entity, EntityMut)>) {}
|
|
|
|
assert_is_system(borrow_mut_system);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore] // This should pass, but it currently fails due to limitations in our access model.
|
|
fn mut_compatible_with_resource() {
|
|
fn borrow_mut_system(_: Res<R>, _: Query<EntityMut>) {}
|
|
|
|
assert_is_system(borrow_mut_system);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore] // This should pass, but it currently fails due to limitations in our access model.
|
|
fn mut_compatible_with_resource_mut() {
|
|
fn borrow_mut_system(_: ResMut<R>, _: Query<EntityMut>) {}
|
|
|
|
assert_is_system(borrow_mut_system);
|
|
}
|
|
|
|
#[test]
|
|
#[should_panic]
|
|
fn mut_incompatible_with_read_only_component() {
|
|
fn incompatible_system(_: Query<(EntityMut, &A)>) {}
|
|
|
|
assert_is_system(incompatible_system);
|
|
}
|
|
|
|
#[test]
|
|
#[should_panic]
|
|
fn mut_incompatible_with_mutable_component() {
|
|
fn incompatible_system(_: Query<(EntityMut, &mut A)>) {}
|
|
|
|
assert_is_system(incompatible_system);
|
|
}
|
|
|
|
#[test]
|
|
#[should_panic]
|
|
fn mut_incompatible_with_read_only_query() {
|
|
fn incompatible_system(_: Query<EntityMut>, _: Query<&A>) {}
|
|
|
|
assert_is_system(incompatible_system);
|
|
}
|
|
|
|
#[test]
|
|
#[should_panic]
|
|
fn mut_incompatible_with_mutable_query() {
|
|
fn incompatible_system(_: Query<EntityMut>, _: Query<&mut A>) {}
|
|
|
|
assert_is_system(incompatible_system);
|
|
}
|
|
}
|