Add ComponentId-taking functions to Entity{Ref,Mut}Except to mirror FilteredEntity{Ref,Mut} (#17800)
# Objective Related to #17784. The ticket is actually about just getting rid of `Entity{Ref,Mut}Except` in favor of `FilteredEntity{Ref,Mut}`, but I got told the unification of Entity types is a bigger endeavor that has been going on for a while now (as the "Pointing Fingers" working group) and I should just add the functions I actually need in the meantime. ## Solution This PR adds all of the functions necessary to access components by TypeId or ComponentId instead of static types. ## Testing > Did you test these changes? If so, how? Haven't tested it yet, but the changes are mostly copy/paste from other implementations in the same file, since there is a lot of duplicated functionality there. ## Not a Migration Guide There shouldn't be any breaking changes, it's just a few new functions on existing types. I had to shuffle around the lifetimes in `From<&EntityMutExcept<'a, B>> for EntityRefExcept<'a, B>` (originally it was `From<&'a EntityMutExcept<'_, B>> for EntityRefExcept<'_, B>`) to make the borrow checker happy, but I don't think that this should have an impact on user code (correct me if I'm wrong).
This commit is contained in:
parent
2fd4cc4937
commit
267a0d003c
@ -3287,6 +3287,24 @@ impl<'a> From<&'a EntityWorldMut<'_>> for FilteredEntityRef<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, B: Bundle> From<&'a EntityRefExcept<'_, B>> for FilteredEntityRef<'a> {
|
||||
fn from(value: &'a EntityRefExcept<'_, B>) -> Self {
|
||||
// SAFETY:
|
||||
// - The FilteredEntityRef has the same component access as the given EntityRefExcept.
|
||||
unsafe {
|
||||
let mut access = Access::default();
|
||||
access.read_all();
|
||||
let components = value.entity.world().components();
|
||||
B::get_component_ids(components, &mut |maybe_id| {
|
||||
if let Some(id) = maybe_id {
|
||||
access.remove_component_read(id);
|
||||
}
|
||||
});
|
||||
FilteredEntityRef::new(value.entity, access)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for FilteredEntityRef<'_> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.entity() == other.entity()
|
||||
@ -3612,6 +3630,24 @@ impl<'a> From<&'a mut EntityWorldMut<'_>> for FilteredEntityMut<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, B: Bundle> From<&'a EntityMutExcept<'_, B>> for FilteredEntityMut<'a> {
|
||||
fn from(value: &'a EntityMutExcept<'_, B>) -> Self {
|
||||
// SAFETY:
|
||||
// - The FilteredEntityMut has the same component access as the given EntityMutExcept.
|
||||
unsafe {
|
||||
let mut access = Access::default();
|
||||
access.write_all();
|
||||
let components = value.entity.world().components();
|
||||
B::get_component_ids(components, &mut |maybe_id| {
|
||||
if let Some(id) = maybe_id {
|
||||
access.remove_component_read(id);
|
||||
}
|
||||
});
|
||||
FilteredEntityMut::new(value.entity, access)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for FilteredEntityMut<'_> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.entity() == other.entity()
|
||||
@ -3737,6 +3773,93 @@ where
|
||||
pub fn spawned_by(&self) -> MaybeLocation {
|
||||
self.entity.spawned_by()
|
||||
}
|
||||
|
||||
/// Gets the component of the given [`ComponentId`] from the entity.
|
||||
///
|
||||
/// **You should prefer to use the typed API [`Self::get`] where possible and only
|
||||
/// use this in cases where the actual component types are not known at
|
||||
/// compile time.**
|
||||
///
|
||||
/// Unlike [`EntityRefExcept::get`], this returns a raw pointer to the component,
|
||||
/// which is only valid while the [`EntityRefExcept`] is alive.
|
||||
#[inline]
|
||||
pub fn get_by_id(&self, component_id: ComponentId) -> Option<Ptr<'w>> {
|
||||
let components = self.entity.world().components();
|
||||
(!bundle_contains_component::<B>(components, component_id))
|
||||
.then(|| {
|
||||
// SAFETY: We have read access for this component
|
||||
unsafe { self.entity.get_by_id(component_id) }
|
||||
})
|
||||
.flatten()
|
||||
}
|
||||
|
||||
/// Returns `true` if the current entity has a component of type `T`.
|
||||
/// Otherwise, this returns `false`.
|
||||
///
|
||||
/// ## Notes
|
||||
///
|
||||
/// If you do not know the concrete type of a component, consider using
|
||||
/// [`Self::contains_id`] or [`Self::contains_type_id`].
|
||||
#[inline]
|
||||
pub fn contains<T: Component>(&self) -> bool {
|
||||
self.contains_type_id(TypeId::of::<T>())
|
||||
}
|
||||
|
||||
/// Returns `true` if the current entity has a component identified by `component_id`.
|
||||
/// Otherwise, this returns false.
|
||||
///
|
||||
/// ## Notes
|
||||
///
|
||||
/// - If you know the concrete type of the component, you should prefer [`Self::contains`].
|
||||
/// - If you know the component's [`TypeId`] but not its [`ComponentId`], consider using
|
||||
/// [`Self::contains_type_id`].
|
||||
#[inline]
|
||||
pub fn contains_id(&self, component_id: ComponentId) -> bool {
|
||||
self.entity.contains_id(component_id)
|
||||
}
|
||||
|
||||
/// Returns `true` if the current entity has a component with the type identified by `type_id`.
|
||||
/// Otherwise, this returns false.
|
||||
///
|
||||
/// ## Notes
|
||||
///
|
||||
/// - If you know the concrete type of the component, you should prefer [`Self::contains`].
|
||||
/// - If you have a [`ComponentId`] instead of a [`TypeId`], consider using [`Self::contains_id`].
|
||||
#[inline]
|
||||
pub fn contains_type_id(&self, type_id: TypeId) -> bool {
|
||||
self.entity.contains_type_id(type_id)
|
||||
}
|
||||
|
||||
/// Retrieves the change ticks for the given component. This can be useful for implementing change
|
||||
/// detection in custom runtimes.
|
||||
#[inline]
|
||||
pub fn get_change_ticks<T: Component>(&self) -> Option<ComponentTicks> {
|
||||
let component_id = self.entity.world().components().get_id(TypeId::of::<T>())?;
|
||||
let components = self.entity.world().components();
|
||||
(!bundle_contains_component::<B>(components, component_id))
|
||||
.then(|| {
|
||||
// SAFETY: We have read access
|
||||
unsafe { self.entity.get_change_ticks::<T>() }
|
||||
})
|
||||
.flatten()
|
||||
}
|
||||
|
||||
/// Retrieves the change ticks for the given [`ComponentId`]. This can be useful for implementing change
|
||||
/// detection in custom runtimes.
|
||||
///
|
||||
/// **You should prefer to use the typed API [`Self::get_change_ticks`] where possible and only
|
||||
/// use this in cases where the actual component types are not known at
|
||||
/// compile time.**
|
||||
#[inline]
|
||||
pub fn get_change_ticks_by_id(&self, component_id: ComponentId) -> Option<ComponentTicks> {
|
||||
let components = self.entity.world().components();
|
||||
(!bundle_contains_component::<B>(components, component_id))
|
||||
.then(|| {
|
||||
// SAFETY: We have read access
|
||||
unsafe { self.entity.get_change_ticks_by_id(component_id) }
|
||||
})
|
||||
.flatten()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, B> From<&'a EntityMutExcept<'_, B>> for EntityRefExcept<'a, B>
|
||||
@ -3894,6 +4017,78 @@ where
|
||||
pub fn spawned_by(&self) -> MaybeLocation {
|
||||
self.entity.spawned_by()
|
||||
}
|
||||
|
||||
/// Returns `true` if the current entity has a component of type `T`.
|
||||
/// Otherwise, this returns `false`.
|
||||
///
|
||||
/// ## Notes
|
||||
///
|
||||
/// If you do not know the concrete type of a component, consider using
|
||||
/// [`Self::contains_id`] or [`Self::contains_type_id`].
|
||||
#[inline]
|
||||
pub fn contains<T: Component>(&self) -> bool {
|
||||
self.contains_type_id(TypeId::of::<T>())
|
||||
}
|
||||
|
||||
/// Returns `true` if the current entity has a component identified by `component_id`.
|
||||
/// Otherwise, this returns false.
|
||||
///
|
||||
/// ## Notes
|
||||
///
|
||||
/// - If you know the concrete type of the component, you should prefer [`Self::contains`].
|
||||
/// - If you know the component's [`TypeId`] but not its [`ComponentId`], consider using
|
||||
/// [`Self::contains_type_id`].
|
||||
#[inline]
|
||||
pub fn contains_id(&self, component_id: ComponentId) -> bool {
|
||||
self.entity.contains_id(component_id)
|
||||
}
|
||||
|
||||
/// Returns `true` if the current entity has a component with the type identified by `type_id`.
|
||||
/// Otherwise, this returns false.
|
||||
///
|
||||
/// ## Notes
|
||||
///
|
||||
/// - If you know the concrete type of the component, you should prefer [`Self::contains`].
|
||||
/// - If you have a [`ComponentId`] instead of a [`TypeId`], consider using [`Self::contains_id`].
|
||||
#[inline]
|
||||
pub fn contains_type_id(&self, type_id: TypeId) -> bool {
|
||||
self.entity.contains_type_id(type_id)
|
||||
}
|
||||
|
||||
/// Gets the component of the given [`ComponentId`] from the entity.
|
||||
///
|
||||
/// **You should prefer to use the typed API [`Self::get`] where possible and only
|
||||
/// use this in cases where the actual component types are not known at
|
||||
/// compile time.**
|
||||
///
|
||||
/// Unlike [`EntityMutExcept::get`], this returns a raw pointer to the component,
|
||||
/// which is only valid while the [`EntityMutExcept`] is alive.
|
||||
#[inline]
|
||||
pub fn get_by_id(&'w self, component_id: ComponentId) -> Option<Ptr<'w>> {
|
||||
self.as_readonly().get_by_id(component_id)
|
||||
}
|
||||
|
||||
/// Gets a [`MutUntyped`] of the component of the given [`ComponentId`] from the entity.
|
||||
///
|
||||
/// **You should prefer to use the typed API [`Self::get_mut`] where possible and only
|
||||
/// use this in cases where the actual component types are not known at
|
||||
/// compile time.**
|
||||
///
|
||||
/// Unlike [`EntityMutExcept::get_mut`], this returns a raw pointer to the component,
|
||||
/// which is only valid while the [`EntityMutExcept`] is alive.
|
||||
#[inline]
|
||||
pub fn get_mut_by_id<F: DynamicComponentFetch>(
|
||||
&mut self,
|
||||
component_id: ComponentId,
|
||||
) -> Option<MutUntyped<'_>> {
|
||||
let components = self.entity.world().components();
|
||||
(!bundle_contains_component::<B>(components, component_id))
|
||||
.then(|| {
|
||||
// SAFETY: We have write access
|
||||
unsafe { self.entity.get_mut_by_id(component_id).ok() }
|
||||
})
|
||||
.flatten()
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: Bundle> PartialEq for EntityMutExcept<'_, B> {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user