mirror of
https://github.com/bevyengine/bevy
synced 2025-01-25 03:15:20 +00:00
a2b5d7a198
# Objective Fix some nightly warnings found by running `cargo +nightly clippy` ## Solution Fix the following warnings: - [x] [elided_lifetimes_in_associated_constant](https://github.com/rust-lang/rust/issues/115010)221986134d
- [x] [unwrap_or_default](https://rust-lang.github.io/rust-clippy/master/index.html#/unwrap_or_default)32e21c78f9
- [x] [needless_pass_by_ref_mut](https://rust-lang.github.io/rust-clippy/master/index.html#/needless_pass_by_ref_mut)c85d6d4a10
There is no breaking change, some internal `bevy_ecs` code no longer uses a few mutable references but I don't think it should cause any regression or be performance sensitive, but there might be some ECS magic I'm unaware of that could break because of those changes
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` gurantees 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` gurantees exclusive access to all of the entity's components.
|
|
// - `&value` ensures there are no mutable accesses.
|
|
unsafe { EntityRef::new(value.0) }
|
|
}
|
|
}
|
|
|
|
/// Provides mutable access to a single entity and all of its components.
|
|
///
|
|
/// Contrast with [`EntityWorldMut`], with allows adding and removing components,
|
|
/// despawning the entity, and provides mutable access to the entire world.
|
|
/// Because of this, `EntityWorldMut` cannot coexist with any other world accesses.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// Disjoint mutable access.
|
|
///
|
|
/// ```
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// # #[derive(Component)] pub struct A;
|
|
/// fn disjoint_system(
|
|
/// query1: Query<EntityMut, With<A>>,
|
|
/// query2: Query<EntityMut, Without<A>>,
|
|
/// ) {
|
|
/// // ...
|
|
/// }
|
|
/// # bevy_ecs::system::assert_is_system(disjoint_system);
|
|
/// ```
|
|
pub struct EntityMut<'w>(UnsafeEntityCell<'w>);
|
|
|
|
impl<'w> EntityMut<'w> {
|
|
/// # Safety
|
|
/// - `cell` must have permission to mutate every component of the entity.
|
|
/// - No accesses to any of the entity's components may exist
|
|
/// at the same time as the returned [`EntityMut`].
|
|
pub(crate) unsafe fn new(cell: UnsafeEntityCell<'w>) -> Self {
|
|
Self(cell)
|
|
}
|
|
|
|
/// Returns a new instance with a shorter lifetime.
|
|
/// This is useful if you have `&mut EntityMut`, but you need `EntityMut`.
|
|
pub fn reborrow(&mut self) -> EntityMut<'_> {
|
|
// SAFETY: We have exclusive access to the entire entity and its components.
|
|
unsafe { Self::new(self.0) }
|
|
}
|
|
|
|
/// Gets read-only access to all of the entity's components.
|
|
pub fn as_readonly(&self) -> EntityRef<'_> {
|
|
EntityRef::from(self)
|
|
}
|
|
|
|
/// Returns the [ID](Entity) of the current entity.
|
|
#[inline]
|
|
#[must_use = "Omit the .id() call if you do not need to store the `Entity` identifier."]
|
|
pub fn id(&self) -> Entity {
|
|
self.0.id()
|
|
}
|
|
|
|
/// Gets metadata indicating the location where the current entity is stored.
|
|
#[inline]
|
|
pub fn location(&self) -> EntityLocation {
|
|
self.0.location()
|
|
}
|
|
|
|
/// Returns the archetype that the current entity belongs to.
|
|
#[inline]
|
|
pub fn archetype(&self) -> &Archetype {
|
|
self.0.archetype()
|
|
}
|
|
|
|
/// Returns `true` if the current entity has a component of type `T`.
|
|
/// Otherwise, this returns `false`.
|
|
///
|
|
/// ## Notes
|
|
///
|
|
/// If you do not know the concrete type of a component, consider using
|
|
/// [`Self::contains_id`] or [`Self::contains_type_id`].
|
|
#[inline]
|
|
pub fn contains<T: Component>(&self) -> bool {
|
|
self.contains_type_id(TypeId::of::<T>())
|
|
}
|
|
|
|
/// Returns `true` if the current entity has a component identified by `component_id`.
|
|
/// Otherwise, this returns false.
|
|
///
|
|
/// ## Notes
|
|
///
|
|
/// - If you know the concrete type of the component, you should prefer [`Self::contains`].
|
|
/// - If you know the component's [`TypeId`] but not its [`ComponentId`], consider using
|
|
/// [`Self::contains_type_id`].
|
|
#[inline]
|
|
pub fn contains_id(&self, component_id: ComponentId) -> bool {
|
|
self.0.contains_id(component_id)
|
|
}
|
|
|
|
/// Returns `true` if the current entity has a component with the type identified by `type_id`.
|
|
/// Otherwise, this returns false.
|
|
///
|
|
/// ## Notes
|
|
///
|
|
/// - If you know the concrete type of the component, you should prefer [`Self::contains`].
|
|
/// - If you have a [`ComponentId`] instead of a [`TypeId`], consider using [`Self::contains_id`].
|
|
#[inline]
|
|
pub fn contains_type_id(&self, type_id: TypeId) -> bool {
|
|
self.0.contains_type_id(type_id)
|
|
}
|
|
|
|
/// Gets access to the component of type `T` for the current entity.
|
|
/// Returns `None` if the entity does not have a component of type `T`.
|
|
#[inline]
|
|
pub fn get<T: Component>(&self) -> Option<&'_ T> {
|
|
self.as_readonly().get()
|
|
}
|
|
|
|
/// Gets access to the component of type `T` for the current entity,
|
|
/// including change detection information as a [`Ref`].
|
|
///
|
|
/// Returns `None` if the entity does not have a component of type `T`.
|
|
#[inline]
|
|
pub fn get_ref<T: Component>(&self) -> Option<Ref<'_, T>> {
|
|
self.as_readonly().get_ref()
|
|
}
|
|
|
|
/// Gets mutable access to the component of type `T` for the current entity.
|
|
/// Returns `None` if the entity does not have a component of type `T`.
|
|
#[inline]
|
|
pub fn get_mut<T: Component>(&mut self) -> Option<Mut<'_, T>> {
|
|
// SAFETY: &mut self implies exclusive access for duration of returned value
|
|
unsafe { self.0.get_mut() }
|
|
}
|
|
|
|
/// Retrieves the change ticks for the given component. This can be useful for implementing change
|
|
/// detection in custom runtimes.
|
|
#[inline]
|
|
pub fn get_change_ticks<T: Component>(&self) -> Option<ComponentTicks> {
|
|
self.as_readonly().get_change_ticks::<T>()
|
|
}
|
|
|
|
/// Retrieves the change ticks for the given [`ComponentId`]. This can be useful for implementing change
|
|
/// detection in custom runtimes.
|
|
///
|
|
/// **You should prefer to use the typed API [`EntityWorldMut::get_change_ticks`] where possible and only
|
|
/// use this in cases where the actual component types are not known at
|
|
/// compile time.**
|
|
#[inline]
|
|
pub fn get_change_ticks_by_id(&self, component_id: ComponentId) -> Option<ComponentTicks> {
|
|
self.as_readonly().get_change_ticks_by_id(component_id)
|
|
}
|
|
|
|
/// Gets the component of the given [`ComponentId`] from the entity.
|
|
///
|
|
/// **You should prefer to use the typed API [`EntityWorldMut::get`] where possible and only
|
|
/// use this in cases where the actual component types are not known at
|
|
/// compile time.**
|
|
///
|
|
/// Unlike [`EntityMut::get`], this returns a raw pointer to the component,
|
|
/// which is only valid while the [`EntityMut`] is alive.
|
|
#[inline]
|
|
pub fn get_by_id(&self, component_id: ComponentId) -> Option<Ptr<'_>> {
|
|
self.as_readonly().get_by_id(component_id)
|
|
}
|
|
|
|
/// Gets a [`MutUntyped`] of the component of the given [`ComponentId`] from the entity.
|
|
///
|
|
/// **You should prefer to use the typed API [`EntityMut::get_mut`] where possible and only
|
|
/// use this in cases where the actual component types are not known at
|
|
/// compile time.**
|
|
///
|
|
/// Unlike [`EntityMut::get_mut`], this returns a raw pointer to the component,
|
|
/// which is only valid while the [`EntityMut`] is alive.
|
|
#[inline]
|
|
pub fn get_mut_by_id(&mut self, component_id: ComponentId) -> Option<MutUntyped<'_>> {
|
|
// SAFETY:
|
|
// - `&mut self` ensures that no references exist to this entity's components.
|
|
// - `as_unsafe_world_cell` gives mutable permission for all components on this entity
|
|
unsafe { self.0.get_mut_by_id(component_id) }
|
|
}
|
|
}
|
|
|
|
impl<'w> From<EntityWorldMut<'w>> for EntityMut<'w> {
|
|
fn from(value: EntityWorldMut<'w>) -> Self {
|
|
// SAFETY: `EntityWorldMut` guarantees exclusive access to the entire world.
|
|
unsafe { EntityMut::new(value.into_unsafe_entity_cell()) }
|
|
}
|
|
}
|
|
|
|
impl<'a> From<&'a mut EntityWorldMut<'_>> for EntityMut<'a> {
|
|
fn from(value: &'a mut EntityWorldMut<'_>) -> Self {
|
|
// SAFETY: `EntityWorldMut` guarantees exclusive access to the entire world.
|
|
unsafe { EntityMut::new(value.as_unsafe_entity_cell()) }
|
|
}
|
|
}
|
|
|
|
/// A mutable reference to a particular [`Entity`], and the entire world.
|
|
/// This is essentially a performance-optimized `(Entity, &mut World)` tuple,
|
|
/// which caches the [`EntityLocation`] to reduce duplicate lookups.
|
|
///
|
|
/// Since this type provides mutable access to the entire world, only one
|
|
/// [`EntityWorldMut`] can exist at a time for a given world.
|
|
///
|
|
/// See also [`EntityMut`], which allows disjoint mutable access to multiple
|
|
/// entities at once. Unlike `EntityMut`, this type allows adding and
|
|
/// removing components, and despawning the entity.
|
|
pub struct EntityWorldMut<'w> {
|
|
world: &'w mut World,
|
|
entity: Entity,
|
|
location: EntityLocation,
|
|
}
|
|
|
|
impl<'w> 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);
|
|
}
|
|
}
|