Add get_ref to EntityRef (#8818)
# Objective To mirror the `Ref` added as `WorldQuery`, and the `Mut` in `EntityMut::get_mut`, we add `EntityRef::get_ref`, which retrieves `T` with tick information, but *immutably*. ## Solution - Add the method in question, also add it to`UnsafeEntityCell` since this seems to be the best way of getting that information. Also update/add safety comments to neighboring code. --- ## Changelog - Add `EntityRef::get_ref` to get an `Option<Ref<T>>` from `EntityRef` --------- Co-authored-by: James Liu <contact@jamessliu.com>
This commit is contained in:
		
							parent
							
								
									001b3eb97c
								
							
						
					
					
						commit
						019432af2e
					
				| @ -12,7 +12,7 @@ use bevy_ptr::{OwningPtr, Ptr}; | ||||
| use bevy_utils::tracing::debug; | ||||
| use std::any::TypeId; | ||||
| 
 | ||||
| use super::unsafe_world_cell::UnsafeEntityCell; | ||||
| use super::{unsafe_world_cell::UnsafeEntityCell, Ref}; | ||||
| 
 | ||||
| /// A read-only reference to a particular [`Entity`] and all of its components
 | ||||
| #[derive(Copy, Clone)] | ||||
| @ -121,6 +121,16 @@ impl<'w> EntityRef<'w> { | ||||
|         unsafe { self.as_unsafe_world_cell_readonly().get::<T>() } | ||||
|     } | ||||
| 
 | ||||
|     /// Gets access to the component of type `T` for the current entity,
 | ||||
|     /// including change detection information as a [`Ref`].
 | ||||
|     ///
 | ||||
|     /// Returns `None` if the entity does not have a component of type `T`.
 | ||||
|     #[inline] | ||||
|     pub fn get_ref<T: Component>(&self) -> Option<Ref<'w, T>> { | ||||
|         // SAFETY: &self implies shared access for duration of returned value
 | ||||
|         unsafe { self.as_unsafe_world_cell_readonly().get_ref::<T>() } | ||||
|     } | ||||
| 
 | ||||
|     /// Retrieves the change ticks for the given component. This can be useful for implementing change
 | ||||
|     /// detection in custom runtimes.
 | ||||
|     #[inline] | ||||
|  | ||||
| @ -2,11 +2,11 @@ | ||||
| 
 | ||||
| #![warn(unsafe_op_in_unsafe_fn)] | ||||
| 
 | ||||
| use super::{Mut, World, WorldId}; | ||||
| use super::{Mut, Ref, World, WorldId}; | ||||
| use crate::{ | ||||
|     archetype::{Archetype, ArchetypeComponentId, Archetypes}, | ||||
|     bundle::Bundles, | ||||
|     change_detection::{MutUntyped, TicksMut}, | ||||
|     change_detection::{MutUntyped, Ticks, TicksMut}, | ||||
|     component::{ | ||||
|         ComponentId, ComponentStorage, ComponentTicks, Components, StorageType, Tick, TickCells, | ||||
|     }, | ||||
| @ -652,10 +652,10 @@ impl<'w> UnsafeEntityCell<'w> { | ||||
|     #[inline] | ||||
|     pub unsafe fn get<T: Component>(self) -> Option<&'w T> { | ||||
|         let component_id = self.world.components().get_id(TypeId::of::<T>())?; | ||||
| 
 | ||||
|         // SAFETY:
 | ||||
|         // - entity location is valid
 | ||||
|         // - proper world access is promised by caller
 | ||||
|         // - `storage_type` is correct (T component_id + T::STORAGE_TYPE)
 | ||||
|         // - `location` is valid
 | ||||
|         // - proper aliasing is promised by caller
 | ||||
|         unsafe { | ||||
|             get_component( | ||||
|                 self.world, | ||||
| @ -669,6 +669,36 @@ impl<'w> UnsafeEntityCell<'w> { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// # Safety
 | ||||
|     /// It is the callers responsibility to ensure that
 | ||||
|     /// - the [`UnsafeEntityCell`] has permission to access the component
 | ||||
|     /// - no other mutable references to the component exist at the same time
 | ||||
|     #[inline] | ||||
|     pub unsafe fn get_ref<T: Component>(self) -> Option<Ref<'w, T>> { | ||||
|         let last_change_tick = self.world.last_change_tick(); | ||||
|         let change_tick = self.world.change_tick(); | ||||
|         let component_id = self.world.components().get_id(TypeId::of::<T>())?; | ||||
| 
 | ||||
|         // SAFETY:
 | ||||
|         // - `storage_type` is correct (T component_id + T::STORAGE_TYPE)
 | ||||
|         // - `location` is valid
 | ||||
|         // - proper aliasing is promised by caller
 | ||||
|         unsafe { | ||||
|             get_component_and_ticks( | ||||
|                 self.world, | ||||
|                 component_id, | ||||
|                 T::Storage::STORAGE_TYPE, | ||||
|                 self.entity, | ||||
|                 self.location, | ||||
|             ) | ||||
|             .map(|(value, cells)| Ref { | ||||
|                 // SAFETY: returned component is of type T
 | ||||
|                 value: value.deref::<T>(), | ||||
|                 ticks: Ticks::from_tick_cells(cells, last_change_tick, change_tick), | ||||
|             }) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Retrieves the change ticks for the given component. This can be useful for implementing change
 | ||||
|     /// detection in custom runtimes.
 | ||||
|     ///
 | ||||
| @ -761,6 +791,7 @@ impl<'w> UnsafeEntityCell<'w> { | ||||
|                 self.location, | ||||
|             ) | ||||
|             .map(|(value, cells)| Mut { | ||||
|                 // SAFETY: returned component is of type T
 | ||||
|                 value: value.assert_unique().deref_mut::<T>(), | ||||
|                 ticks: TicksMut::from_tick_cells(cells, last_change_tick, change_tick), | ||||
|             }) | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Nicola Papale
						Nicola Papale