Support using FilteredResources with ReflectResource. (#15624)
# Objective Support accessing resources using reflection when using `FilteredResources` in a dynamic system. This is similar to how components can be queried using reflection when using `FilteredEntityRef|Mut`. ## Solution Change `ReflectResource` from taking `&World` and `&mut World` to taking `impl Into<FilteredResources>` and `impl Into<FilteredResourcesMut>`, similar to how `ReflectComponent` takes `impl Into<FilteredEntityRef>` and `impl Into<FilteredEntityMut>`. There are `From` impls that ensure code passing `&World` and `&mut World` continues to work as before. ## Migration Guide If you are manually creating a `ReflectComponentFns` struct, the `reflect` function now takes `FilteredResources` instead `&World`, and there is a new `reflect_mut` function that takes `FilteredResourcesMut`.
This commit is contained in:
parent
d7fd00a8b9
commit
0a32450715
@ -8,7 +8,7 @@ use crate::{
|
||||
change_detection::Mut,
|
||||
component::ComponentId,
|
||||
resource::Resource,
|
||||
world::{unsafe_world_cell::UnsafeWorldCell, World},
|
||||
world::{unsafe_world_cell::UnsafeWorldCell, FilteredResources, FilteredResourcesMut, World},
|
||||
};
|
||||
use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, TypePath, TypeRegistry};
|
||||
|
||||
@ -52,7 +52,9 @@ pub struct ReflectResourceFns {
|
||||
/// Function pointer implementing [`ReflectResource::remove()`].
|
||||
pub remove: fn(&mut World),
|
||||
/// Function pointer implementing [`ReflectResource::reflect()`].
|
||||
pub reflect: fn(&World) -> Option<&dyn Reflect>,
|
||||
pub reflect: for<'w> fn(FilteredResources<'w, '_>) -> Option<&'w dyn Reflect>,
|
||||
/// Function pointer implementing [`ReflectResource::reflect_mut()`].
|
||||
pub reflect_mut: for<'w> fn(FilteredResourcesMut<'w, '_>) -> Option<Mut<'w, dyn Reflect>>,
|
||||
/// Function pointer implementing [`ReflectResource::reflect_unchecked_mut()`].
|
||||
///
|
||||
/// # Safety
|
||||
@ -111,14 +113,23 @@ impl ReflectResource {
|
||||
}
|
||||
|
||||
/// Gets the value of this [`Resource`] type from the world as a reflected reference.
|
||||
pub fn reflect<'a>(&self, world: &'a World) -> Option<&'a dyn Reflect> {
|
||||
(self.0.reflect)(world)
|
||||
///
|
||||
/// Note that [`&World`](World) is a valid type for `resources`.
|
||||
pub fn reflect<'w, 's>(
|
||||
&self,
|
||||
resources: impl Into<FilteredResources<'w, 's>>,
|
||||
) -> Option<&'w dyn Reflect> {
|
||||
(self.0.reflect)(resources.into())
|
||||
}
|
||||
|
||||
/// Gets the value of this [`Resource`] type from the world as a mutable reflected reference.
|
||||
pub fn reflect_mut<'a>(&self, world: &'a mut World) -> Option<Mut<'a, dyn Reflect>> {
|
||||
// SAFETY: unique world access
|
||||
unsafe { (self.0.reflect_unchecked_mut)(world.as_unsafe_world_cell()) }
|
||||
///
|
||||
/// Note that [`&mut World`](World) is a valid type for `resources`.
|
||||
pub fn reflect_mut<'w, 's>(
|
||||
&self,
|
||||
resources: impl Into<FilteredResourcesMut<'w, 's>>,
|
||||
) -> Option<Mut<'w, dyn Reflect>> {
|
||||
(self.0.reflect_mut)(resources.into())
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
@ -212,7 +223,12 @@ impl<R: Resource + FromReflect + TypePath> FromType<R> for ReflectResource {
|
||||
remove: |world| {
|
||||
world.remove_resource::<R>();
|
||||
},
|
||||
reflect: |world| world.get_resource::<R>().map(|res| res as &dyn Reflect),
|
||||
reflect: |world| world.get::<R>().map(|res| res.into_inner() as &dyn Reflect),
|
||||
reflect_mut: |world| {
|
||||
world
|
||||
.into_mut::<R>()
|
||||
.map(|res| res.map_unchanged(|value| value as &mut dyn Reflect))
|
||||
},
|
||||
reflect_unchecked_mut: |world| {
|
||||
// SAFETY: all usages of `reflect_unchecked_mut` guarantee that there is either a single mutable
|
||||
// reference or multiple immutable ones alive at any given point
|
||||
|
@ -715,9 +715,11 @@ mod tests {
|
||||
use crate::{
|
||||
entity::Entities,
|
||||
prelude::{Component, Query},
|
||||
reflect::ReflectResource,
|
||||
system::{Local, RunSystemOnce},
|
||||
};
|
||||
use alloc::vec;
|
||||
use bevy_reflect::{FromType, Reflect, ReflectRef};
|
||||
|
||||
use super::*;
|
||||
|
||||
@ -730,8 +732,11 @@ mod tests {
|
||||
#[derive(Component)]
|
||||
struct C;
|
||||
|
||||
#[derive(Resource, Default)]
|
||||
struct R;
|
||||
#[derive(Resource, Default, Reflect)]
|
||||
#[reflect(Resource)]
|
||||
struct R {
|
||||
foo: usize,
|
||||
}
|
||||
|
||||
fn local_system(local: Local<u64>) -> u64 {
|
||||
*local
|
||||
@ -1071,4 +1076,31 @@ mod tests {
|
||||
.build_state(&mut world)
|
||||
.build_system(|_r: ResMut<R>, _fr: FilteredResourcesMut| {});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn filtered_resource_reflect() {
|
||||
let mut world = World::new();
|
||||
world.insert_resource(R { foo: 7 });
|
||||
|
||||
let system = (FilteredResourcesParamBuilder::new(|builder| {
|
||||
builder.add_read::<R>();
|
||||
}),)
|
||||
.build_state(&mut world)
|
||||
.build_system(|res: FilteredResources| {
|
||||
let reflect_resource = <ReflectResource as FromType<R>>::from_type();
|
||||
let ReflectRef::Struct(reflect_struct) =
|
||||
reflect_resource.reflect(res).unwrap().reflect_ref()
|
||||
else {
|
||||
panic!()
|
||||
};
|
||||
*reflect_struct
|
||||
.field("foo")
|
||||
.unwrap()
|
||||
.try_downcast_ref::<usize>()
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
let output = world.run_system_once(system).unwrap();
|
||||
assert_eq!(output, 7);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user