mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 12:43:34 +00:00
Generalize component reflection to operate on FilteredEntityRef
and FilteredEntityMut
, not EntityRef
and EntityMut
. (#13549)
Currently, either an `EntityRef` or `EntityMut` is required in order to reflect a component on an entity. This can, however, be generalized to `FilteredEntityRef` and `FilteredEntityMut`, which are versions of `EntityRef` and `EntityMut` that restrict the components that can be accessed. This is useful because dynamic queries yield `FilteredEntityRef` and `FilteredEntityMut` rows when iterated over. This commit changes `ReflectComponent::contains()`, `ReflectComponent::reflect()`, and `ReflectComponent::reflect_mut()` to take an `Into<FilteredEntityRef>` (in the case of `contains()` and `reflect()`) and `Into<FilteredEntityMut>` (in the case of `reflect_mut()`). Fortunately, `EntityRef` and `EntityMut` already implement the corresponding trait, so nothing else has to be done to the public API. Note that in order to implement `ReflectComponent::reflect_mut()` properly, an additional method `FilteredEntityMut::into_mut()` was required, to match the one on `EntityMut`. I ran into this when attempting to implement `QUERY` in the Bevy Remote Protocol when trying to iterate over rows of dynamic queries and fetch the associated components without unsafe code. There were other potential ways to work around this problem, but they required either reimplementing the query logic myself instead of using regular Bevy queries or storing entity IDs and then issuing another query to fetch the associated `EntityRef`. Both of these seemed worse than just improving the `reflect()` function. ## Migration Guide * `ReflectComponent::contains`, `ReflectComponent::reflect`, and `ReflectComponent::reflect_mut` now take `FilteredEntityRef` (in the case of `contains()` and `reflect()`) and `FilteredEntityMut` (in the case of `reflect_mut()`) parameters. `FilteredEntityRef` and `FilteredEntityMut` have very similar APIs to `EntityRef` and `EntityMut` respectively, but optionally restrict the components that can be accessed.
This commit is contained in:
parent
d98d6d8d00
commit
05288ffa32
2 changed files with 25 additions and 9 deletions
|
@ -62,7 +62,10 @@ use crate::{
|
|||
change_detection::Mut,
|
||||
component::Component,
|
||||
entity::Entity,
|
||||
world::{unsafe_world_cell::UnsafeEntityCell, EntityMut, EntityRef, EntityWorldMut, World},
|
||||
world::{
|
||||
unsafe_world_cell::UnsafeEntityCell, EntityMut, EntityWorldMut, FilteredEntityMut,
|
||||
FilteredEntityRef, World,
|
||||
},
|
||||
};
|
||||
use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry};
|
||||
|
||||
|
@ -104,11 +107,11 @@ pub struct ReflectComponentFns {
|
|||
/// Function pointer implementing [`ReflectComponent::remove()`].
|
||||
pub remove: fn(&mut EntityWorldMut),
|
||||
/// Function pointer implementing [`ReflectComponent::contains()`].
|
||||
pub contains: fn(EntityRef) -> bool,
|
||||
pub contains: fn(FilteredEntityRef) -> bool,
|
||||
/// Function pointer implementing [`ReflectComponent::reflect()`].
|
||||
pub reflect: fn(EntityRef) -> Option<&dyn Reflect>,
|
||||
pub reflect: fn(FilteredEntityRef) -> Option<&dyn Reflect>,
|
||||
/// Function pointer implementing [`ReflectComponent::reflect_mut()`].
|
||||
pub reflect_mut: fn(EntityMut) -> Option<Mut<dyn Reflect>>,
|
||||
pub reflect_mut: fn(FilteredEntityMut) -> Option<Mut<dyn Reflect>>,
|
||||
/// Function pointer implementing [`ReflectComponent::reflect_unchecked_mut()`].
|
||||
///
|
||||
/// # Safety
|
||||
|
@ -165,19 +168,19 @@ impl ReflectComponent {
|
|||
}
|
||||
|
||||
/// Returns whether entity contains this [`Component`]
|
||||
pub fn contains(&self, entity: EntityRef) -> bool {
|
||||
(self.0.contains)(entity)
|
||||
pub fn contains<'a>(&self, entity: impl Into<FilteredEntityRef<'a>>) -> bool {
|
||||
(self.0.contains)(entity.into())
|
||||
}
|
||||
|
||||
/// Gets the value of this [`Component`] type from the entity as a reflected reference.
|
||||
pub fn reflect<'a>(&self, entity: EntityRef<'a>) -> Option<&'a dyn Reflect> {
|
||||
(self.0.reflect)(entity)
|
||||
pub fn reflect<'a>(&self, entity: impl Into<FilteredEntityRef<'a>>) -> Option<&'a dyn Reflect> {
|
||||
(self.0.reflect)(entity.into())
|
||||
}
|
||||
|
||||
/// Gets the value of this [`Component`] type from the entity as a mutable reflected reference.
|
||||
pub fn reflect_mut<'a>(
|
||||
&self,
|
||||
entity: impl Into<EntityMut<'a>>,
|
||||
entity: impl Into<FilteredEntityMut<'a>>,
|
||||
) -> Option<Mut<'a, dyn Reflect>> {
|
||||
(self.0.reflect_mut)(entity.into())
|
||||
}
|
||||
|
|
|
@ -2102,6 +2102,19 @@ impl<'w> FilteredEntityMut<'w> {
|
|||
.flatten()
|
||||
}
|
||||
|
||||
/// Consumes self and gets mutable access to the component of type `T`
|
||||
/// with the world `'w` lifetime for the current entity.
|
||||
/// Returns `None` if the entity does not have a component of type `T`.
|
||||
#[inline]
|
||||
pub fn into_mut<T: Component>(self) -> Option<Mut<'w, T>> {
|
||||
let id = self.entity.world().components().get_id(TypeId::of::<T>())?;
|
||||
self.access
|
||||
.has_write(id)
|
||||
// SAFETY: We have write access
|
||||
.then(|| unsafe { self.entity.get_mut() })
|
||||
.flatten()
|
||||
}
|
||||
|
||||
/// Retrieves the change ticks for the given component. This can be useful for implementing change
|
||||
/// detection in custom runtimes.
|
||||
#[inline]
|
||||
|
|
Loading…
Reference in a new issue